복붙노트

PHP FOR에서 FOREACH의 성능

PHP

PHP FOR에서 FOREACH의 성능

우선, 90 %의 응용 프로그램에서 성능 차이가 전혀 관련이 없다는 것을 알고 있지만, 더 빠른 구조가 무엇인지 알아야합니다. 그것과 ...

그물에 그 (것)들에 현재 유효한 정보는 복잡합니다. 많은 사람들은 foreach가 좋지 않다고 말하지만 기술적으로는 반복자를 사용하여 배열 순회를 단순화한다고 가정하기 때문에 기술적으로 더 빨라야합니다. 반복자는 다시 빠르지 만 PHP에서는 죽은 것처럼 느껴진다 (또는 PHP가 아닌가?). 나는 배열 함수에 대해 말하고있다 : next () prev () reset () 등등. 함수가 짝수이고 함수처럼 보이는 PHP 언어 기능 중 하나가 아니라면 말이다.

이 점을 조금 좁히려면 : 1 이상의 단계로 배열을 순회하는 것은 흥미롭지 않습니다 (부정적인 단계도 없기 때문에 역순으로 반복합니다). 나는 또한 임의의 점을 통과하는 데 관심이 없으며 길이는 0에 불과하다. 나는 또한 1000 개 이상의 키가 정기적으로 발생하는 배열을 조작하는 것을 보지 못했지만 배열 논리가 응용 프로그램의 논리에서 여러 번 통과하는 것을 보았습니다! 또한 조작의 경우에는 주로 문자열 조작 및 반향 만합니다.

다음은 참조 사이트가 거의없는 경우입니다. http://www.phpbench.com/ http://www.php.lt/benchmark/phpbench.php

내가 들려주는 모든 것 :

여기 내 문제가있다. 나는이 테스트 스크립트를 작성했다 : http://pastebin.com/1ZgK07US 그리고 내가 스크립트를 몇 번이나 실행했는지 상관없이 나는 다음과 같은 것을 얻는다.

foreach 1.1438131332397
foreach (using reference) 1.2919359207153
for 1.4262869358063
foreach (hash table) 1.5696921348572
for (hash table) 2.4778981208801

간단히 말해서 :

누군가 설명 할 수 있습니까?

PHP 버전 5.3.0 편집 : 답변 여기에있는 사람들의 도움으로 나는 모든 질문에 대한 해답을 모을 수있었습니다. 여기서 요약 해 보겠습니다.

도와 주신 모든 분들께 감사드립니다.

모든 간단한 탐색을 위해 foreach (참조가 아닌 버전)를 사용합니다.

해결법

  1. ==============================

    1.나의 개인 의견은 맥락에서 의미가있는 것을 사용하는 것이다. 개인적으로 나는 배열 탐색을 위해 거의 사용하지 않는다. 다른 유형의 반복에도 사용하지만 foreach는 너무 쉽습니다 ... 대부분의 경우 시간 차이는 최소화 될 것입니다.

    나의 개인 의견은 맥락에서 의미가있는 것을 사용하는 것이다. 개인적으로 나는 배열 탐색을 위해 거의 사용하지 않는다. 다른 유형의 반복에도 사용하지만 foreach는 너무 쉽습니다 ... 대부분의 경우 시간 차이는 최소화 될 것입니다.

    감시해야 할 가장 중요한 사항은 다음과 같습니다.

    for ($i = 0; $i < count($array); $i++) {
    

    매 반복마다 카운트를하기 때문에 값 비싼 루프입니다. 네가 그렇게하지 않는 한, 나는 그것이 정말로 중요하다고 생각하지 않는다.

    차이점을 만드는 참조에 관해서 PHP는 copy-on-write를 사용하므로 배열에 쓰지 않는다면 루핑하는 동안 오버 헤드가 상대적으로 적을 것입니다. 그러나 배열 내에서 배열을 수정하기 시작하면 각 배열 사이에 차이점이 표시되기 시작합니다 (전체 배열을 복사해야하므로 참조가 인라인으로 수정 될 수 있음).

    이터레이터의 경우 foreach는 다음과 같습니다.

    $it->rewind();
    while ($it->valid()) {
        $key = $it->key();     // If using the $key => $value syntax
        $value = $it->current();
    
        // Contents of loop in here
    
        $it->next();
    }
    

    반복 할 수있는 더 빠른 방법이있는 한 문제는 실제로 문제에 달려 있습니다. 그러나 나는 정말로 물을 필요가있다, 왜? 보다 효율적인 작업을 원한다는 것을 이해하지만 마이크로 최적화에 시간을 낭비하고 있다고 생각합니다. 조기 최적화는 모든 악의 근원임을 기억하십시오.

    편집 : 의견을 바탕으로, 나는 빠른 벤치 마크를 실행하기로 결정 ...

    $a = array();
    for ($i = 0; $i < 10000; $i++) {
        $a[] = $i;
    }
    
    $start = microtime(true);
    foreach ($a as $k => $v) {
        $a[$k] = $v + 1;
    }
    echo "Completed in ", microtime(true) - $start, " Seconds\n";
    
    $start = microtime(true);
    foreach ($a as $k => &$v) {
        $v = $v + 1;
    }
    echo "Completed in ", microtime(true) - $start, " Seconds\n";
    
    $start = microtime(true);
    foreach ($a as $k => $v) {}
    echo "Completed in ", microtime(true) - $start, " Seconds\n";
    
    $start = microtime(true);
    foreach ($a as $k => &$v) {}    
    echo "Completed in ", microtime(true) - $start, " Seconds\n";
    

    결과 :

    Completed in 0.0073502063751221 Seconds
    Completed in 0.0019769668579102 Seconds
    Completed in 0.0011849403381348 Seconds
    Completed in 0.00111985206604 Seconds
    

    따라서 루프에서 배열을 수정하는 경우 참조를 사용하는 것이 몇 배 빠릅니다 ...

    그리고 참조에 대한 오버 헤드는 실제로 배열을 복사하는 것보다 작습니다 (5.3.2에 있음) ... 그래서 참조가 상당히 빨라진 것처럼 (적어도 5.3.2에서) 나타납니다.

  2. ==============================

    2.나는 이것이 매우 놀랍다 고 확신하지 못한다. PHP를 코딩하는 대부분의 사람들은 PHP가 베어 메탈에서 실제로하고있는 것에 정통하지 않습니다. 나는 몇 가지 사실을 말할 것인데, 그것은 대부분의 경우 사실 일 것이다.

    나는 이것이 매우 놀랍다 고 확신하지 못한다. PHP를 코딩하는 대부분의 사람들은 PHP가 베어 메탈에서 실제로하고있는 것에 정통하지 않습니다. 나는 몇 가지 사실을 말할 것인데, 그것은 대부분의 경우 사실 일 것이다.

    이러한 이유 때문에 foreach는 단순한 반복을위한 최선의 선택입니다.

    잊지 마세요. 읽기 쉽기 때문에 윈 - 윈 (win-win)입니다.

  3. ==============================

    3.벤치마킹 (특히 ​​phpbench.com)에서 주목해야 할 것은 숫자가 건전하지만 테스트가 아니라는 것입니다. phpbench.com의 테스트 중 많은 부분이 사소한 일이며, 벤치 마크를 왜곡하기 위해 배열 조회를 캐싱하는 PHP의 능력이나 배열을 반복하는 경우 실제로 실제 사례에서는 테스트하지 않습니다. 루프). 나는 내가 본 자신의 벤치 마크를 실제 결과를 상당히 반영하고 있으며, 언어의 네이티브 반복 구문 foreach가 항상 놀랍게 나오는 것을 보여줍니다.

    벤치마킹 (특히 ​​phpbench.com)에서 주목해야 할 것은 숫자가 건전하지만 테스트가 아니라는 것입니다. phpbench.com의 테스트 중 많은 부분이 사소한 일이며, 벤치 마크를 왜곡하기 위해 배열 조회를 캐싱하는 PHP의 능력이나 배열을 반복하는 경우 실제로 실제 사례에서는 테스트하지 않습니다. 루프). 나는 내가 본 자신의 벤치 마크를 실제 결과를 상당히 반영하고 있으며, 언어의 네이티브 반복 구문 foreach가 항상 놀랍게 나오는 것을 보여줍니다.

    //make a nicely random array
    $aHash1 = range( 0, 999999 );
    $aHash2 = range( 0, 999999 );
    shuffle( $aHash1 );
    shuffle( $aHash2 );
    $aHash = array_combine( $aHash1, $aHash2 );
    
    
    $start1 = microtime(true);
    foreach($aHash as $key=>$val) $aHash[$key]++;
    $end1 = microtime(true);
    
    $start2 = microtime(true);
    while(list($key) = each($aHash)) $aHash[$key]++;
    $end2 = microtime(true);
    
    
    $start3 = microtime(true);
    $key = array_keys($aHash);
    $size = sizeOf($key);
    for ($i=0; $i<$size; $i++) $aHash[$key[$i]]++;
    $end3 = microtime(true);
    
    $start4 = microtime(true);
    foreach($aHash as &$val) $val++;
    $end4 = microtime(true);
    
    echo "foreach ".($end1 - $start1)."\n"; //foreach 0.947947025299
    echo "while ".($end2 - $start2)."\n"; //while 0.847212076187
    echo "for ".($end3 - $start3)."\n"; //for 0.439476966858
    echo "foreach ref ".($end4 - $start4)."\n"; //foreach ref 0.0886030197144
    
    //For these tests we MUST do an array lookup,
    //since that is normally the *point* of iteration
    //i'm also calling noop on it so that PHP doesn't
    //optimize out the loopup.
    function noop( $value ) {}
    
    //Create an array of increasing indexes, w/ random values
    $bHash = range( 0, 999999 );
    shuffle( $bHash );
    
    $bstart1 = microtime(true);
    for($i = 0; $i < 1000000; ++$i) noop( $bHash[$i] );
    $bend1 = microtime(true);
    
    $bstart2 = microtime(true);
    $i = 0; while($i < 1000000) { noop( $bHash[$i] ); ++$i; }
    $bend2 = microtime(true);
    
    
    $bstart3 = microtime(true);
    foreach( $bHash as $value ) { noop( $value ); }
    $bend3 = microtime(true);
    
    echo "for ".($bend1 - $bstart1)."\n"; //for 0.397135972977
    echo "while ".($bend2 - $bstart2)."\n"; //while 0.364789962769
    echo "foreach ".($bend3 - $bstart3)."\n"; //foreach 0.346374034882
    
  4. ==============================

    4.제 생각에는 확실하지 않습니다 : for 루프는 값을 확인하고 증가시키기 위해 두 가지 연산을 필요로합니다. foreach는 메모리에 데이터를로드 한 다음 모든 값을 반복합니다.

    제 생각에는 확실하지 않습니다 : for 루프는 값을 확인하고 증가시키기 위해 두 가지 연산을 필요로합니다. foreach는 메모리에 데이터를로드 한 다음 모든 값을 반복합니다.

  5. from https://stackoverflow.com/questions/3430194/performance-of-for-vs-foreach-in-php by cc-by-sa and MIT license