Heim > Backend-Entwicklung > PHP-Tutorial > Speicherleistung steigert mit Generatoren und Nikic/Iter

Speicherleistung steigert mit Generatoren und Nikic/Iter

Joseph Gordon-Levitt
Freigeben: 2025-02-16 09:17:10
Original
454 Leute haben es durchsucht

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.

Memory Performance Boosts with Generators and Nikic/Iter

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

  • Generatoren (verfügbar, da PHP 5.5 verfügbar ist) sind leistungsstarke Tools zum Erstellen von Iteratoren, die die Erstellung interruptierbarer, wiederholbarer Funktionen ermöglichen, die Verarbeitung großer Datensätze vereinfachen und die Speicherleistung verbessern.
  • nikita popov erstellt eine Nikic/Iter -Bibliothek, die Funktionen einführt, die mit Iteratoren und Generatoren verwendet werden können, wodurch ein erheblichem Speicher speichert, indem es vermeiden, unnötige Zwischenarrays zu erstellen.
  • Die Bibliotheken Generator und Nikic/Iter sind besonders nützlich, wenn sie mit großen CSV -Dateien arbeiten, die große Datensätze verarbeiten können, ohne sie alle gleichzeitig in Speicher zu laden.
  • Während Generatoren die Speicherleistung erheblich verbessern können, stellen sie auch einige ihrer eigenen Herausforderungen vor, wie z. array_filter array_map
Frage

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")
);
Nach dem Login kopieren
Nach dem Login kopieren

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);
Nach dem Login kopieren
Nach dem Login kopieren

(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());
Nach dem Login kopieren
Nach dem Login kopieren
, mit dem Sie diese CSV -Dateien erstellen können ...)

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")
);
Nach dem Login kopieren
Nach dem Login kopieren

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);
Nach dem Login kopieren
Nach dem Login kopieren

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());
Nach dem Login kopieren
Nach dem Login kopieren

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);
}
Nach dem Login kopieren

Dies kann einfacher sein:

foreach (readCSVGenerator("posts.csv") as $post) {
    // 使用 $post 执行某些操作
}

print "memory:" . formatBytes(memory_get_peak_usage());
Nach dem Login kopieren

(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
Nach dem Login kopieren

Sie können Funktionen wie slice und take verwenden, um Schnitte iterierbarer Variablen zurückzugeben:

// ... (后续代码与原文类似,但使用iter库函数进行优化,此处省略以节省篇幅) ...
Nach dem Login kopieren

Wenn Sie Generatoren mehr verwenden, stellen Sie möglicherweise fest, dass Sie sie nicht immer wiederverwenden müssen. Betrachten Sie das folgende Beispiel:

// ... (使用iter库函数简化代码,此处省略以节省篇幅) ...
Nach dem Login kopieren

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函数的示例代码,此处省略以节省篇幅) ...
Nach dem Login kopieren

Sie können diese Zuordnungsfunktion mehrmals verwenden. Sie können sogar Ihren eigenen Generator wiederspulen lassen:

// ... (使用iter\slice和iter\toArray函数的示例代码,此处省略以节省篇幅) ...
Nach dem Login kopieren

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!

Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage