Let op: Tweakers stopt per 2023 met Tweakblogs. In
dit artikel
leggen we uit waarom we hiervoor hebben gekozen.
Devblogjes
De snelste manier om een array te prefix in php
Voor het ontwikkelen van een grote applicatie op mijn werk was ik benieuwd naar de performance van php met betrekking tot het prefixen van waarden in array. Je kunt wel zeggen dat dit valt onder premature optimalisation, maar met zicht op de verschillen denk ik wel dat het handig is er rekening mee te houden vanaf het begin.
De tests zijn gedaan door een array te vullen met 30.000 integers en deze te prefixen met de string 'prefix'. Voor deze testcase zijn dit de resultaten, met daaronder de code:
Duidelijk is dus dat het gebruik van de wazige constructie implode/explode het snelst is, maar wel wat extra geheugengebruik heeft t.o.v. de for-constructie. *!*
Array_walk is veruit de traagste functie met het meeste geheugengebruik, iets wat je opzich niet zou verwachten.
Qua geheugengebruik is de for-functie veruit superieur, en qua snelheid doet hij niet veel onder voor de explode/implode foreach met reference.
Tenzij je echt met enorme arrays gaat werken maken deze optimalisaties natuurlijk niet echt uit, maar wel verwonderlijk de verschillen te zien
*!* Na een opmerking van Erkens bleek dat niet de explode/implode-methode het snelst is, maar een foreach met een reference naar het object. De implode/explode volgt als tweede, en de for-loop is de nummer 3. Een iets andere conclusie dus
Hieronder de code, niet de mooiste, maar het was natuurlijk maar om te testen:
De tests zijn gedaan door een array te vullen met 30.000 integers en deze te prefixen met de string 'prefix'. Voor deze testcase zijn dit de resultaten, met daaronder de code:
| Test | Tijd | Extra geheugengebruik |
|---|---|---|
| Array_walk met method | 0.0266440 | 2,097,152B |
| Explode / implode | 0.0109251 | 786,432B |
| For-loop | 0.0115969 | 0B |
| For-loop met method | 0.0215051 | 0B |
| Foreach | 0.0135100 | 1,048,576B |
| Foreach met reference | 0.0100880 | 0B |
Duidelijk is dus dat het gebruik van de wazige constructie implode/explode het snelst is, maar wel wat extra geheugengebruik heeft t.o.v. de for-constructie. *!*
Array_walk is veruit de traagste functie met het meeste geheugengebruik, iets wat je opzich niet zou verwachten.
Qua geheugengebruik is de for-functie veruit superieur, en qua snelheid doet hij niet veel onder voor de explode/implode foreach met reference.
Tenzij je echt met enorme arrays gaat werken maken deze optimalisaties natuurlijk niet echt uit, maar wel verwonderlijk de verschillen te zien
*!* Na een opmerking van Erkens bleek dat niet de explode/implode-methode het snelst is, maar een foreach met een reference naar het object. De implode/explode volgt als tweede, en de for-loop is de nummer 3. Een iets andere conclusie dus
Hieronder de code, niet de mooiste, maar het was natuurlijk maar om te testen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
| $aItems = array_fill(0, 30000, 1234); // create array with 30k items $sPre = 'prefix'; function test1(&$s, $k, $sPre) { $s = $sPre.$s; } function test4($s, $sPre) { return $sPre.$s; } // TEST 1 - Array_Walk to prefix $iMemBefore = memory_get_usage(true); $iTmp = microtime(true); array_walk($aItems, 'test1', $sPre); echo '1: '. str_pad(round((microtime(true) - $iTmp), 7), 9,'0') . ' (array_walk) - Mem '.number_format((memory_get_usage(true) - $iMemBefore)).'B'; // reset $aItems = array_fill(0, 30000, 1234); // create array with 30k items // TEST 2 - implode/explode to prefix $iMemBefore = memory_get_usage(true); $iTmp = microtime(true); $aItems = explode('|', $sPre.implode('|'.$sPre, $aItems)); echo '<br />2: '. str_pad(round((microtime(true) - $iTmp), 7), 9,'0') . ' (explode/implode) - Mem '.number_format((memory_get_usage(true) - $iMemBefore)).'B'; // reset $aItems = array_fill(0, 30000, 1234); // create array with 30k items // TEST 3 - for loop $iMemBefore = memory_get_usage(true); $iTmp = microtime(true); $iCount = count($aItems); for($i = 0; $i < $iCount; $i++) { $aItems[$i] = $sPre.$aItems[$i]; } echo '<br />3: '. str_pad(round((microtime(true) - $iTmp), 7), 9,'0') . ' (for) - Mem '.number_format((memory_get_usage(true) - $iMemBefore)).'B'; // reset $aItems = array_fill(0, 30000, 1234); // create array with 30k items // TEST 4 - for loop with method call $iMemBefore = memory_get_usage(true); $iTmp = microtime(true); $iCount = count($aItems); for($i = 0; $i < $iCount; $i++) { $aItems[$i] = test4($aItems[$i], $sPre); } echo '<br />4: '. str_pad(round((microtime(true) - $iTmp), 7), 9,'0') . ' (for - method) - Mem '.number_format((memory_get_usage(true) - $iMemBefore)).'B'; // reset $aItems = array_fill(0, 30000, 1234); // create array with 30k items // TEST 5 - foreach loop $iMemBefore = memory_get_usage(true); $iTmp = microtime(true); $aNew = array(); foreach($aItems as $sKey => $iItem) { $aNew[$sKey] = $sPre.$iItem; } echo '<br />5: '. str_pad(round((microtime(true) - $iTmp), 7), 9,'0') . ' (foreach) - Mem '.number_format((memory_get_usage(true) - $iMemBefore)).'B'; // reset $aItems = array_fill(0, 30000, 1234); // create array with 30k items // TEST 6 - foreach loop - own array - reference $iMemBefore = memory_get_usage(true); $iTmp = microtime(true); // // Note the & // // foreach($aItems as $sKey => &$iItem) { $iItem = $sPre.$iItem; } echo '<br />6: '. str_pad(round((microtime(true) - $iTmp), 7), 9,'0') . ' (foreach - own array - reference) - Mem '.number_format((memory_get_usage(true) - $iMemBefore)).'B'; |