PHP -Iterator und Generator: Ein leistungsstarkes Tool zur effizienten Verarbeitung großer Datensätze
Arrays und Iterationen sind der Eckpfeiler jeder Anwendung. Wenn wir neue Tools erhalten, sollte sich auch die Art und Weise, wie wir Arrays verwenden, verbessern.
zum Beispiel ist ein Generator ein neues Werkzeug. Zuerst haben wir nur Arrays, und dann erlangen wir die Fähigkeit, unsere eigene Klassenarray -Struktur (als Iteratoren bezeichnet) zu definieren. Seit PHP 5.5 können wir jedoch schnell Klassen -Iteratorstrukturen erstellen, die als Generatoren bezeichnet werden.
Der Generator sieht aus wie Funktionen, aber wir können sie als Iteratoren verwenden. Sie bieten uns eine einfache Syntax, um im Wesentlichen unterbrechbare, wiederholbare Funktionen zu erstellen. Sie sind unglaublich!
Wir werden mehrere Bereiche betrachten, in denen Generatoren verwendet werden können, und einige Probleme untersuchen, auf die bei der Verwendung von Generatoren geachtet werden müssen. Schließlich werden wir eine großartige Bibliothek lernen, die vom talentierten Nikita Popov erstellt wurde.
Der Beispielcode finden Sie unter https://github.com/sitepoint-editors/generators-and-iter.
Schlüsselpunkte
array_filter
array_map
Angenommen, Sie haben viele relationale Daten und möchten einige Vorspannungen vornehmen. Möglicherweise sind die Daten von Kommas getrennt. Sie müssen jeden Datentyp laden und zusammen gruppieren.
Sie können mit dem folgenden einfachen Code beginnen:
Sie können dann versuchen, verwandte Elemente durch Iterieren oder höhere Ordnung zu verkettet:
function readCSV($file) { $rows = []; $handle = fopen($file, "r"); while (!feof($handle)) { $rows[] = fgetcsv($handle); } fclose($handle); return $rows; } $authors = array_filter( readCSV("authors.csv") ); $categories = array_filter( readCSV("categories.csv") ); $posts = array_filter( readCSV("posts.csv") );
Sieht gut aus, oder? Was passiert also, wenn wir eine große Anzahl von CSV -Dateien analysieren können? Lassen Sie uns die Speicherverwendung ein wenig analysieren ...
function filterByColumn($array, $column, $value) { return array_filter( $array, function($item) use ($column, $value) { return $item[$column] == $value; } ); } $authors = array_map(function($author) use ($posts) { $author["posts"] = filterByColumn( $posts, 1, $author[0] ); // 对 $author 进行其他更改 return $author; }, $authors); $categories = array_map(function($category) use ($posts) { $category["posts"] = filterByColumn( $posts, 2, $category[0] ); // 对 $category 进行其他更改 return $category; }, $categories); $posts = array_map(function($post) use ($authors, $categories) { foreach ($authors as $author) { if ($author[0] == $post[1]) { $post["author"] = $author; break; } } foreach ($categories as $category) { if ($category[0] == $post[1]) { $post["category"] = $category; break; } } // 对 $post 进行其他更改 return $post; }, $posts);
(Der Beispielcode enthält
function formatBytes($bytes, $precision = 2) { $kilobyte = 1024; $megabyte = 1024 * 1024; if ($bytes >= 0 && $bytes < $kilobyte) { return $bytes . " b"; } if ($bytes >= $kilobyte && $bytes < $megabyte) { return round($bytes / $kilobyte, $precision) . " kb"; } return round($bytes / $megabyte, $precision) . " mb"; } print "memory:" . formatBytes(memory_get_peak_usage());
generate.php
Wenn Sie über große CSV -Dateien verfügen, sollte dieser Code angezeigt, wie viel Speicher erforderlich ist, um diese Arrays miteinander zu verknüpfen. Mindestens die gleiche Größe wie die Datei, die Sie lesen müssen, da PHP alles im Speicher halten muss.
Generator kommt, um zu retten!
Eine Möglichkeit, dieses Problem zu verbessern, besteht darin, einen Generator zu verwenden. Wenn Sie mit ihnen nicht vertraut sind, ist jetzt ein guter Zeitpunkt, um mehr zu lernen.
Mit dem Generator können Sie eine kleine Menge an Gesamtdaten gleichzeitig laden. Sie müssen nicht viel mit dem Generator machen:
function readCSV($file) { $rows = []; $handle = fopen($file, "r"); while (!feof($handle)) { $rows[] = fgetcsv($handle); } fclose($handle); return $rows; } $authors = array_filter( readCSV("authors.csv") ); $categories = array_filter( readCSV("categories.csv") ); $posts = array_filter( readCSV("posts.csv") );
Wenn Sie CSV -Daten iterieren, werden Sie feststellen, dass die erforderliche Menge an Speicher sofort reduziert wird:
function filterByColumn($array, $column, $value) { return array_filter( $array, function($item) use ($column, $value) { return $item[$column] == $value; } ); } $authors = array_map(function($author) use ($posts) { $author["posts"] = filterByColumn( $posts, 1, $author[0] ); // 对 $author 进行其他更改 return $author; }, $authors); $categories = array_map(function($category) use ($posts) { $category["posts"] = filterByColumn( $posts, 2, $category[0] ); // 对 $category 进行其他更改 return $category; }, $categories); $posts = array_map(function($post) use ($authors, $categories) { foreach ($authors as $author) { if ($author[0] == $post[1]) { $post["author"] = $author; break; } } foreach ($categories as $category) { if ($category[0] == $post[1]) { $post["category"] = $category; break; } } // 对 $post 进行其他更改 return $post; }, $posts);
Wenn Sie zuvor Megabyte der Speichernutzung gesehen haben, werden Sie jetzt Kilobytes sehen. Dies ist eine enorme Verbesserung, aber nicht ohne Probleme.
Zunächst array_filter
und array_map
funktionieren nicht mit Generatoren. Sie müssen andere Tools finden, um diese Art von Daten zu verarbeiten. Hier ist ein Werkzeug, das Sie versuchen können!
function formatBytes($bytes, $precision = 2) { $kilobyte = 1024; $megabyte = 1024 * 1024; if ($bytes >= 0 && $bytes < $kilobyte) { return $bytes . " b"; } if ($bytes >= $kilobyte && $bytes < $megabyte) { return round($bytes / $kilobyte, $precision) . " kb"; } return round($bytes / $megabyte, $precision) . " mb"; } print "memory:" . formatBytes(memory_get_peak_usage());
Diese Bibliothek führt einige Funktionen ein, die mit Iteratoren und Generatoren verwendet werden können. Wie erhalten Sie also noch all diese relevanten Daten, ohne Daten im Speicher zu speichern?
function readCSVGenerator($file) { $handle = fopen($file, "r"); while (!feof($handle)) { yield fgetcsv($handle); } fclose($handle); }
Dies kann einfacher sein:
foreach (readCSVGenerator("posts.csv") as $post) { // 使用 $post 执行某些操作 } print "memory:" . formatBytes(memory_get_peak_usage());
(Jeden Mal jede Datenquelle neu zu lesen ist jedes Mal ineffizient. Erwägen Sie, kleinere verwandte Daten (wie Autoren und Kategorien) im Speicher zu speichern.
Andere interessante Dinge
Für Nikics Bibliothek ist dies nur die Spitze des Eisbergs! Wollten Sie schon immer ein Array (oder Iterator/Generator) abflachen?
composer require nikic/iter
Sie können Funktionen wie slice
und take
verwenden, um Schnitte iterierbarer Variablen zurückzugeben:
// ... (后续代码与原文类似,但使用iter库函数进行优化,此处省略以节省篇幅) ...
Wenn Sie Generatoren mehr verwenden, stellen Sie möglicherweise fest, dass Sie sie nicht immer wiederverwenden müssen. Betrachten Sie das folgende Beispiel:
// ... (使用iter库函数简化代码,此处省略以节省篇幅) ...
Wenn Sie versuchen, den Code auszuführen, sehen Sie eine Ausnahme, die aufzufordern: "Der geschlossene Generator kann nicht durchqueren". Jede Iteratorfunktion in dieser Bibliothek hat eine austauschbare entsprechende Funktion:
// ... (使用iter\flatten和iter\toArray函数的示例代码,此处省略以节省篇幅) ...
Sie können diese Zuordnungsfunktion mehrmals verwenden. Sie können sogar Ihren eigenen Generator wiederspulen lassen:
// ... (使用iter\slice和iter\toArray函数的示例代码,此处省略以节省篇幅) ...
Was Sie daraus erhalten, ist ein wiederverwendbarer Generator!
Schlussfolgerung
Für jeden Schleifenbetrieb, den Sie berücksichtigen müssen, ist der Generator möglicherweise eine Option. Sie sind sogar nützlich für andere Dinge. Wenn Sprachmerkmale nicht ausreichend sind, bietet die Nikic-Bibliothek eine große Anzahl von Funktionen höherer Ordnung.
Verwenden Sie bereits den Generator? Möchten Sie weitere Beispiele dafür sehen, wie Sie sie in Ihrer eigenen Anwendung für einige Leistungsverbesserungen implementieren können? Bitte sagen Sie es uns!
(Der FAQS -Teil ähnelt dem Originaltext und wird hier weggelassen, um Platz zu sparen. Der FAQS -Teil kann nach Bedarf optional aufbewahrt oder neu organisiert werden.)
Das obige ist der detaillierte Inhalt vonSpeicherleistung steigert mit Generatoren und Nikic/Iter. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!