PHP: array_key_exists sucht 500-mal schneller als in_array

2014 haben sie bereits über die Suche nach dem Array geschrieben , aber kaum jemand hat es verstanden.

Seitdem wurden viele Versionen von PHP veröffentlicht und nicht behoben, was bedeutet, dass das Feedback schlecht ist und nur wenige Menschen davon wissen. Auf Python ist es dasselbe und in 3 * schlechter als in 2.7.

Manchmal müssen Sie eine Zeichenfolge in einem Array von Zeichenfolgen finden - eine sehr häufige Operation in verschiedenen Algorithmen. Wenn das Array klein ist und ein wenig und nicht in einer Schleife aussieht, wirkt sich in_array normal auf die Gesamtgeschwindigkeit aus. Wenn Sie jedoch große Datenmengen benötigen und nach einem Array mit einer Milliarde Zeilen und einer Milliarde suchen , dann ist das entscheidend: bessere Stunde statt Woche.

Ein einfacher Test zeigt:

in_array sucht in 6-9 Sekunden nach ideone.com/Yb1mDa 6600ms
und array_key_exists sucht nach demselben, aber schneller als 250 (php5.6 / py3. *) 400+ mal (php7.3 / py2.7) ideone .com / gwSmFc(Zyklus um das 100-fache erhöht) 12 ms (6600/12 = 550-fache + -10% Streuung aufgrund von Last und Cache)

Warum geschieht dies? Betrachten Sie im Detail:

1) Um Strings in reinen Assemblern zu finden, wird ein Array von Strings (schnell oder blasig) sortiert und anschließend binär gesucht.

Die Anzahl der Schritte in einem binären Suchprotokoll (n) hängt von der Größe des Arrays ab und ist viel kleiner als eine einfache Suche.

Sie können ein Array von Zeichenfolgen im Voraus einmal sortieren und zwischenspeichern und dann eine Milliarde Suchvorgänge durchführen. Das hilft aber nicht.

Standardmäßig erfolgt die Sortierung jedes Mal erneut, obwohl sie geschrieben haben, dass sie sich in 7.2 in_array durch einen Hash verbessert haben, aber nicht viel.

2) Suchen Sie den Index / Schlüssel (als Zeichenfolge) in der Zuordnung. Array / Wörterbuch erfolgt durch Hash von Strings und Kollisionsverarbeitung (Hash-Suchfehler). Ein Hash ist der numerische Index des Arrays und wird in 2 Schritten als (Adresse des Nullelements) + Offset * die Größe des Zeigers auf das Array von Zeichenfolgen mit diesem Hash abgerufen. + Brute-Force-Kollisionen, Schritte im Durchschnitt weniger als die binäre Suche.
Der Index-Hash wird beim Erstellen des Wörterbuchelements $ m [key] = val automatisch einmal im Voraus ausgeführt und zwischengespeichert.

Die Größe des Hashs, der Hash-Algorithmus, ist in die PHP-Engine eingenäht und kann nicht geändert werden. Obwohl der Quellcode geöffnet ist, können Sie ihn herunterladen, um ihn zu ändern und zu kompilieren, wenn Ihr Server.

Sie können nicht weiter lesen, in_array in array_combine + array_key_exists ändern und fertig.

Die Anzahl der Schritte bei der Suche nach Hash hängt von der Anzahl der Kollisionen und der Anzahl der Zeilen mit demselben Hash ab. Sie müssen aussortiert oder auch sortiert und binär gesucht werden.

Um Kollisionen zu reduzieren, können Sie mehr Speicher zuweisen, wenn es möglich ist, dass dies jetzt kein Problem mehr ist wie vor 50 Jahren, als 1 KB Speicher auf Magnetspulen wie ein Flugzeug kostet. Und dann wurden alle grundlegenden Algorithmen erfunden: sort / zip / gif / jpg / etc. - sie brauchen nicht viel Speicher, aber sie sind schlecht, jetzt sind sie viel besser, aber sie brauchen viel Speicher 1-16 MB. Ja, es gibt Server mit 256 MB und jeder hat einen eigenen Stream und 16 MB sind bereits viel, aber auf dem Gerät eines durchschnittlichen Benutzers mindestens 1 GB und 16 MB ist ein Tropfen auf den heißen Stein.

Sie können noch mehr Wirkung erzielen, wenn Sie den Aufruf der Funktion array_key_exists durch das Konstrukt isset ($ m [key]) ersetzen, die Befehlswarteschlange und den Cache nicht löschen, den Stapel nicht verwenden und um etwa 20% schneller sind.

Sie können es auch beschleunigen, wenn Sie ein Array aus den ersten beiden Buchstaben - 4 * 16 KB - erstellen und zuerst den Versatz (Index = Code des 1. Zeichens + 2. * 256) eines Zeigers auf das Hash-Array für den Rest der Zeile betrachten und dann nach einem kleinen Array von „Schwänzen“ von Zeichenfolgen suchen und Kollisionen sind viel kleiner.

Es benötigt noch mehr Speicher und der Algorithmus ist komplizierter, aber die Suche ist mehr als 30-mal schneller. Dies ist jedoch nicht in PHP implementiert. Sie können Ihre so / dll-Bibliothek schreiben und aufrufen oder Entwickler bitten, sie in 7.5 hinzuzufügen.

Sie können mySQL durchsuchen, aber Sie müssen Abfragen gruppieren, und es wird immer noch langsamer.

PS: Diese Methode wurde versehentlich durch Tippen, Intuition und Erfahrung gefunden, als ich eine große langsame Website beschleunigte. Es gibt viele solche Feinheiten und Tricks. Ich habe es geschafft, die zu exportierenden Daten von 40 Sekunden auf 0,8 Sekunden zu bringen, Listen mit Sortierung und Filtern auszugeben und viele andere Dinge, bei denen Standardtechniken, Frameworks und Frameworks alles zu langsam machen, obwohl sie natürlich praktisch sind und die Entwicklung beschleunigen.

All Articles