Zunächst einmal verstehe ich, dass in 90% der Anwendungen der Leistungsunterschied völlig irrelevant ist, aber ich muss nur wissen, welches das schnellere Konstrukt ist. Das und ...
Die Informationen, die derzeit im Internet verfügbar sind, sind verwirrend. Viele Leute sagen, dass foreach schlecht ist, aber technisch sollte es schneller sein, da es das Schreiben eines Array-Traversals mit Iteratoren vereinfachen soll. Iteratoren, von denen wiederum angenommen wird, dass sie schneller sind, aber in PHP anscheinend auch absolut langsam sind (oder ist dies keine PHP-Sache?). Ich spreche von den Array-Funktionen: next () prev () reset () usw. Nun, wenn es sich um gerade Funktionen handelt und nicht um eine dieser PHP-Sprachfunktionen, die wie Funktionen aussehen.
Um dies ein wenig einzugrenzen : Ich bin nicht daran interessiert, Arrays in Schritten von mehr als 1 zu durchlaufen (auch keine negativen Schritte, dh umgekehrte Iteration). Ich bin auch nicht an einer Durchquerung von und zu beliebigen Punkten interessiert, nur 0 bis zur Länge. Ich sehe auch nicht, dass Arrays mit mehr als 1000 Schlüsseln regelmäßig manipuliert werden, aber ich sehe, dass ein Array in der Logik einer Anwendung mehrmals durchlaufen wird! Auch für Operationen, größtenteils nur String-Manipulation und Echo.
Hier einige Referenzseiten:
http://www.phpbench.com/
http://www.php.lt/benchmark/phpbench.php
Was ich überall höre:
foreach
ist langsam und somitfor
/while
ist schneller- PHPs kopieren
foreach
das Array, über das es iteriert. Um es schneller zu machen, müssen Sie Referenzen verwenden - Code wie folgt : ist schneller als ein
$key = array_keys($aHash); $size = sizeOf($key);
for ($i=0; $i < $size; $i++)foreach
Hier ist mein Problem. Ich habe dieses Testskript geschrieben: http://pastebin.com/1ZgK07US und egal wie oft ich das Skript ausführe, ich erhalte Folgendes:
foreach 1.1438131332397
foreach (using reference) 1.2919359207153
for 1.4262869358063
foreach (hash table) 1.5696921348572
for (hash table) 2.4778981208801
Zusamenfassend:
foreach
ist schneller alsforeach
mit Referenzforeach
ist schneller alsfor
foreach
ist schneller alsfor
für eine Hash-Tabelle
Kann jemand erklären?
- Mache ich etwas falsch?
- Macht PHP für jede Referenz wirklich einen Unterschied? Ich meine, warum sollte es nicht kopiert werden, wenn Sie als Referenz übergeben werden?
- Was ist der äquivalente Iteratorcode für die foreach-Anweisung? Ich habe einige im Netz gesehen, aber jedes Mal, wenn ich sie teste, ist das Timing weit entfernt. Ich habe auch ein paar einfache Iteratorkonstrukte getestet, aber nie anständige Ergebnisse zu erzielen - sind die Array-Iteratoren in PHP einfach schrecklich?
- Gibt es schnellere Möglichkeiten / Methoden / Konstrukte, um durch ein anderes Array als FOR / FOREACH (und WHILE) zu iterieren?
PHP Version 5.3.0
Bearbeiten: Antwort Mit Hilfe der Leute hier konnte ich die Antworten auf alle Fragen zusammensetzen. Ich werde sie hier zusammenfassen:
- "Mache ich etwas falsch?" Der Konsens scheint zu sein: Ja, ich kann Echo nicht in Benchmarks verwenden. Persönlich sehe ich immer noch nicht, wie Echo eine Funktion mit zufälliger Ausführungszeit ist oder wie eine andere Funktion irgendwie anders ist - das und die Fähigkeit dieses Skripts, genau die gleichen Ergebnisse von foreach besser als alles zu generieren, ist schwierig zu erklären, obwohl nur "Sie verwenden Echo" (nun, was hätte ich verwenden sollen). Ich gebe jedoch zu, dass der Test mit etwas Besserem durchgeführt werden sollte; Ein idealer Kompromiss fällt mir jedoch nicht ein.
- "Macht PHP für jede Referenzsache wirklich einen Unterschied? Ich meine, warum sollte es nicht kopiert werden, wenn Sie als Referenz übergeben werden?" ircmaxell zeigt, dass dies der Fall ist. Weitere Tests scheinen zu beweisen, dass die Referenz in den meisten Fällen schneller sein sollte - obwohl angesichts meines obigen Codeausschnitts definitiv nicht alles bedeutet. Ich akzeptiere, dass das Problem wahrscheinlich zu nicht intuitiv ist, um es auf einer solchen Ebene zu behandeln, und dass etwas Extremes wie das Dekompilieren erforderlich wäre, um tatsächlich zu bestimmen, welches für jede Situation besser ist.
- "Was ist der äquivalente Iterator-Code für die foreach-Anweisung? Ich habe einige im Internet gesehen, aber jedes Mal, wenn ich sie teste, ist das Timing weit entfernt. Ich habe auch einige einfache Iterator-Konstrukte getestet, aber nie anständige Ergebnisse zu erzielen - Sind die Array-Iteratoren in PHP einfach schrecklich? " ircmaxell lieferte die Antwort unten; Der Code ist jedoch möglicherweise nur für die PHP-Version> = 5 gültig
- "Gibt es schnellere Möglichkeiten / Methoden / Konstrukte, um durch ein anderes Array als FOR / FOREACH (und WHILE) zu iterieren?" Danke an Gordon für die Antwort. Die Verwendung neuer Datentypen in PHP5 sollte entweder eine Leistungssteigerung oder eine Speichersteigerung bewirken (je nach Ihrer Situation kann dies wünschenswert sein). Während die Geschwindigkeit vieler neuer Array-Typen nicht besser zu sein scheint als array (), scheinen die Splpriorityqueue und der Splobject-Speicher wesentlich schneller zu sein. Link bereitgestellt von Gordon: http://matthewturland.com/2010/05/20/new-spl-features-in-php-5-3/
Vielen Dank an alle, die versucht haben zu helfen.
Ich werde mich wahrscheinlich für jede einfache Durchquerung an foreach (die Nicht-Referenzversion) halten.
Antworten:
Meine persönliche Meinung ist es, das zu verwenden, was im Kontext Sinn macht. Persönlich verwende ich fast nie
for
für Array-Traversal. Ich benutze es für andere Arten der Iteration, aber esforeach
ist einfach zu einfach ... Der Zeitunterschied wird in den meisten Fällen minimal sein.Das Wichtigste ist:
Dies ist eine teure Schleife, da Aufrufe bei jeder einzelnen Iteration zählen. Solange du das nicht tust, denke ich nicht, dass es wirklich wichtig ist ...
Was die Referenz betrifft, die einen Unterschied macht, verwendet PHP Copy-on-Write. Wenn Sie also nicht in das Array schreiben, entsteht beim Schleifen relativ wenig Overhead. Wenn Sie jedoch anfangen, das Array innerhalb des Arrays zu ändern, werden Sie dort Unterschiede zwischen ihnen feststellen (da das gesamte Array kopiert werden muss und die Referenz nur inline geändert werden kann) ...
Was die Iteratoren betrifft,
foreach
entspricht dies:Soweit es schnellere Möglichkeiten zum Iterieren gibt, hängt es wirklich vom Problem ab. Aber ich muss wirklich fragen, warum? Ich verstehe, dass Sie die Dinge effizienter gestalten wollen, aber ich denke, Sie verschwenden Ihre Zeit für eine Mikrooptimierung. Denken Sie daran,
Premature Optimization Is The Root Of All Evil
...Bearbeiten: Aufgrund des Kommentars habe ich mich für einen schnellen Benchmark-Lauf entschieden ...
Und die Ergebnisse:
Wenn Sie also das Array in der Schleife ändern, ist die Verwendung von Referenzen um ein Vielfaches schneller ...
Und der Overhead für nur die Referenz ist tatsächlich geringer als das Kopieren des Arrays (dies ist in 5.3.2) ... Es scheint also (zumindest in 5.3.2), als ob Referenzen wesentlich schneller sind ...
quelle
"the better standard way to adopt."
Leistung von @srcspider ist nicht das einzige Kriterium für die Auswahl der zu verwendenden Elemente . besonders in solch einem weit hergeholten Fall. Ehrlich gesagt, verschwenden Sie nur Ihre ZeitIch bin mir nicht sicher, ob das so überraschend ist. Die meisten Leute, die in PHP programmieren, sind nicht gut darin versiert, was PHP tatsächlich auf dem Bare Metal macht. Ich werde ein paar Dinge sagen, die die meiste Zeit wahr sein werden:
Wenn Sie die Variable nicht ändern, ist der By-Value in PHP schneller. Dies liegt daran, dass die Referenz ohnehin gezählt wird und der Nachwert weniger zu tun gibt. Es weiß, dass ZVAL (die interne Datenstruktur von PHP für die meisten Typen) in der Sekunde, in der Sie es ändern, auf einfache Weise abgebrochen werden muss (kopieren Sie es und vergessen Sie das andere ZVAL). Aber Sie ändern es nie, also spielt es keine Rolle. Referenzen machen dies komplizierter, da mehr Buchhaltung erforderlich ist, um zu wissen, was zu tun ist, wenn Sie die Variable ändern. Wenn Sie also schreibgeschützt sind, ist es paradoxerweise besser, nicht auf das & hinzuweisen. Ich weiß, es ist nicht intuitiv, aber es ist auch wahr.
Foreach ist nicht langsam. Und für eine einfache Iteration wird die Bedingung, gegen die getestet wird - "Bin ich am Ende dieses Arrays" - mit nativem Code und nicht mit PHP-Opcodes ausgeführt. Selbst wenn es sich um APC-zwischengespeicherte Opcodes handelt, ist es immer noch langsamer als eine Reihe nativer Operationen, die am Bare Metal ausgeführt werden.
Die Verwendung einer for-Schleife "für ($ i = 0; $ i <count ($ x); $ i ++) ist aufgrund der count () und der mangelnden Fähigkeit von PHP (oder einer wirklich interpretierten Sprache), bei der Analyse auszuwerten, langsam Zeit, ob irgendetwas das Array ändert. Dies verhindert, dass es die Anzahl einmal auswertet.
Aber selbst wenn Sie es einmal mit "$ c = count ($ x); für ($ i = 0; $ i <$ c; $ i ++) reparieren, ist $ i <$ c bestenfalls eine Reihe von Zend-Opcodes Das $ i ++. Im Verlauf von 100000 Iterationen kann dies von Bedeutung sein. Foreach weiß auf nativer Ebene, was zu tun ist. Es sind keine PHP-Opcodes erforderlich, um die Bedingung "Bin ich am Ende dieses Arrays" zu testen.
Was ist mit der alten Schule? "While (list (" stuff? Nun, die Verwendung von each (), current () usw. wird mindestens einen Funktionsaufruf beinhalten, der nicht langsam, aber nicht kostenlos ist. Ja, diese sind wieder PHP-Opcodes! Also während + Liste + hat jeder auch seine Kosten.
Aus diesen Gründen ist foreach verständlicherweise die beste Option für eine einfache Iteration.
Und vergessen Sie nicht, es ist auch am einfachsten zu lesen, also Win-Win.
quelle
Eine Sache, auf die Sie bei Benchmarks (insbesondere bei phpbench.com) achten sollten, ist, dass die Tests zwar solide sind, die Tests jedoch nicht. Viele der Tests auf phpbench.com sind trivial und missbrauchen die Fähigkeit von PHP, Array-Lookups zwischenzuspeichern, um Benchmarks zu verzerren, oder im Falle des Iterierens über ein Array dies in realen Fällen nicht zu testen (niemand schreibt leer für Schleifen). Ich habe meine eigenen Benchmarks erstellt, die die Ergebnisse der realen Welt widerspiegeln und immer die native iterierende Syntax der Sprache zeigen
foreach
(Überraschung, Überraschung).quelle
Es ist 2020 und die Dinge haben sich mit PHP 7.4 und Opcache stark weiterentwickelt .
Hier ist der OP ^ -Benchmark, der als Unix- CLI ohne die Teile echo und html ausgeführt wird.
Der Test wurde lokal auf einem normalen Computer ausgeführt.
Modifiziertes Benchmark-Skript:
Ausgabe:
Wie Sie sehen können, ist die Entwicklung verrückt, ungefähr 560 Mal schneller als 2012 berichtet.
Auf meinen Maschinen und Servern sind nach meinen zahlreichen Experimenten die Grundlagen für Schleifen am schnellsten. Dies ist mit verschachtelten Schleifen ( $ i $ j $ k ..) noch deutlicher .
Es ist auch am flexibelsten in der Verwendung und hat aus meiner Sicht eine bessere Lesbarkeit.
quelle
Ich denke, aber ich bin nicht sicher: Die
for
Schleife benötigt zwei Operationen zum Überprüfen und Inkrementieren von Werten.foreach
Lädt die Daten in den Speicher, dann werden alle Werte wiederholt.quelle