2017-08-11 28 views
3

我得到這個代碼:雖然&list&each組合比array_walk和foreach在PHP上快得多嗎?

<?php 
// Test results 
$array1 = test('array_walk'); 
$array2 = test('array_walk_list_each'); 
$array3 = test('array_walk_foreach1'); 
$array4 = test('array_walk_foreach2'); 

// Check arrays for equal 
var_dump($array1 == $array2, $array1 == $array3, $array1 == $array4); 

// Test function 1 
function array_walk_list_each(&$array, $function, $userData = null) { 
    while (list($key, $value) = each($array)) 
     $function($array[$key], $key, $userData); 
} 

// Test function 2 
function array_walk_foreach1(&$array, $function, $userData = null) { 
    foreach ($array as $key => &$value) 
     $function($value, $key, $userData); 
} 

// Test function 3 
function array_walk_foreach2(&$array, $function, $userData = null) { 
    foreach ($array as $key => $value) 
     $function($array[$key], $key, $userData); 
} 

function some_function(&$value, $key, $userData) { 
    $value = "$key => $userData"; 
} 

function test($function, $count = 10000, $arrayElements = 1000) { 
    echo $function, ' ... '; 
    $array = array_fill(0, $arrayElements, "some text value"); 

    $timer = microtime(true); 
    for($i = 0; ++$i < $count;) 
     $function($array, 'some_function', 'some user data'); 
    printf("%.3f sec\n", microtime(true) - $timer); 

    return $array; 
} 

的這個輸出是非常困難的,我明白了:

array_walk ... 1.024 sec 
array_walk_list_each ... 0.002 sec 
array_walk_foreach1 ... 1.135 sec 
array_walk_foreach2 ... 1.359 sec 
bool(true) 
bool(true) 
bool(true) 

這些功能之間的性能差異也幾乎是一個笑話。

這怎麼可能?難道我做錯了什麼?

我從使用PHP 7.0

+3

您認爲您在四個函數中迭代數組有多少次?你認爲這對失去三個人是公平的嗎?獲勝函數中的重置($ array)是否會改變? SIA有點自鳴得意。 – jh1711

+1

@ jh1711發佈解答問題的答案。 – Barmar

+1

@Barmer好的我會 – jh1711

回答

2

只是因爲each()需要重置數組以重新遍歷它。所以你在循環函數中有一個單獨的執行。而其他人正在迭代它。

http://php.net/manual/en/function.each.php

你的結果將只生產1的10000行迭代,而其他人則是10000行10000次迭代。

$array = array_fill(0, 10000, uniqid('', false)); 
$fill = []; 
$fill2 = []; 
$timer = microtime(true); 
for ($i = 0; $i < 10; $i++) { 
    while (list($key, $value) = each($array)) { 
     $fill[] = 'value'; 
    } 
} 
printf("While list each %.3f sec\n", microtime(true) - $timer); 
$timer = microtime(true); 
for ($i = 0; $i < 10; $i++) { 
    foreach ($array as $key => $value) { 
     $fill2[] = 'value'; 
    } 
} 
printf("Foreach %.3f sec\n", microtime(true) - $timer); 
var_dump(count($fill), count($fill2)); 

結果:https://3v4l.org/bvNdO


要獲得所有你需要改變array_walk_list_each函數的功能相同的結果。

while (list($key, $value) = each($array)){ 
    $function($array[$key], $key, $userData); 
} 
reset($array); 
+0

但看,我在所有的函數結果中都得到了相同的4個數組,它怎麼可能? – perodriguezl

+0

@perodriguezl在任何函數的第一次迭代之後,您的數組未被更改。沒有添加任何內容,只需更改10,000個值的初始值,其他人也可以這樣做。如果你要做'$ value =「$ key => $ userData」。 ++ $ i;'你會看到遞增的值與其他函數不匹配。 – fyrye

+0

你實際上是這樣做的:https://3v4l.org/Ohr76當這是實際結果。 https://3v4l.org/KIpKU – fyrye

2

的foreach每次運行前復位內部陣列指針,並在每一步向前移動它的終端運行腳本。這意味着你的測試函數將被稱爲10 000 000。數組遍歷根本不使用內部指針,但仍處理每個調用中的每個元素。這就是爲什麼時間可比。

但是,每次使用後,每個指針都會增加內部指針。它不會重置它(谷歌手冊的更多信息)。這意味着你只修改一次數組,並且在以後的運行中不要進入while循環。由於你的some_function是冪等性的,所以你檢查平等通行證,但時間要短得多。

編輯即可添加:重置不必是明確的。考慮此代碼:

function array_walk_list_each_copy(&$array, $function, $userData = null) { 
    $a = $array; 
    while (list($key, $value) = each($a)) 
    $function($array[$key], $key, $userData); 
} 

每個工作在每次數組的一個拷貝,並修改副本,而不是原來的內部指針。它不會擊敗其他功能,但更慢,因爲寫入時複製開銷

+0

以及我如何以4個相等的數組結束? – perodriguezl

+0

您的函數在每次運行中爲每個值分配「一些用戶數據」。這意味着在第一次運行之後,數組並沒有真正改變(在你稱之爲冪等函數的數學中)。這就是爲什麼所有陣列都是平等的。如果您使用不同的功能(例如'$ value = $ value ++')數組將會不同。 – jh1711