2014-05-16 2 views
3

반복기를 반복하려면 foreach을 호출하거나 while 루프를 사용할 수 있습니다. foreach의 구현은 다음과 같습니다 scala Iterator # foreach 성능 문제

def foreach[U](f: A => U) { while (hasNext) f(next()) } 

그래서 내가 foreach 최대한 빨리 while(iterator.hasNext)로하지만, 몇 가지 테스트를 수행 한 후, 결과가 나에게 매우 놀라게한다고 생각합니다.

내 테스트 코드 :

def getSize2[T](i: Iterator[T]) = { 
    var count = 0 
    val f = (a: T) => count += 1 
    while(i.hasNext) { 
    f(i.next) 
    } 
    count 
} 

def getSize3[T](i: Iterator[T]) = { 
    var count = 0 
    val f = (a: T) => count += 1 
    i.foreach(f) 
    count 
} 

getSize2 3 배 빠른 getSize3보다 매우 이상한입니다!

아무도 무슨 일이 있었는지 아십니까?

편집 : 는

def main(args: Array[String]) { 
    val data = 0 to 100000000 

    val start2 = System.nanoTime 
    (0 to 100).foreach(_ => getSize2(data.iterator)) 
    println("get size, while loop, using function: " + (System.nanoTime - start2)/1000000) 

    val start3 = System.nanoTime 
    (0 to 100).foreach(_ => getSize3(data.iterator)) 
    println("get size, foreach: " + (System.nanoTime - start3)/1000000) 

} 

내 OS를 내 테스트 프로그램을 붙여 : 12.04 우분투, 스칼라 버전 : 2.10.3

+1

실행 속도를 측정 한 방법을 쓸 수 있습니까? 나는 당신이 실행 한 실제 코드와 명령 줄을 의미합니다. 추가로 스칼라 버전과 어떤 OS를 실행 중인지 확인하십시오. – ymonad

+1

바이트 코드를 보면 foreach가 더 많은 호출을 수행하고 있음을 알 수 있습니다. – monkjack

+1

나는 그 반대 결과를보고 있기 때문에 흥미 롭습니다. while (iter.hasNext) {count + = 1; iter.next()}는 6 배 더 오래 걸립니다. – Snnappie

답변

4

다음은 함수 호출이 무료하지 않고 항상 할 수 없기 때문에 루프는 빠른 반면 JIT 컴파일러에 의해 제거되었습니다. 특히 var count은 익명 객체로 래핑되어 함수 객체 내에서 액세스 할 수 있으므로 JIT 컴파일러가 모든 것을 처리해야하고 익명 객체가 전혀 필요 없다는 것을 깨달아야합니다.

함수 호출의 추가 레이어를 foreach 라이브러리에 추가하면 JIT 컴파일러의 분석 (두 개가 아닌 간접적 인 3 개 레이어 등)이 복잡해집니다.

+0

또한 while 루프 버전의 익명 함수 객체에서'var count'를 래핑합니다. JIT가 foreach 버전이 아닌 while 루프 버전에서 함수 호출을 제거 할 가능성이 더 높음을 의미합니까? – cloud

+0

@cloud - 네, 그것이 내 뜻입니다. 할 일이 적어 종종 차이가 있습니다. 그것에 대해 명확하게 대답을 편집했습니다. –