De snelste manier om een array te prefix in php

Door krvabo op maandag 10 januari 2011 15:36 - Reacties (25)
Categorie: Dev, Views: 7.351

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:

TestTijdExtra geheugengebruik
Array_walk met method0.02664402,097,152B
Explode / implode0.0109251786,432B
For-loop0.01159690B
For-loop met method0.02150510B
Foreach0.01351001,048,576B
Foreach met reference0.01008800B


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';