Rumah >pembangunan bahagian belakang >tutorial php >Prestasi memori meningkat dengan penjana dan nikic/iter
php iterator dan penjana: alat yang berkuasa untuk pemprosesan yang cekap set data besar
array dan lelaran adalah asas kepada sebarang permohonan. Apabila kita mendapat alat baru, cara kita menggunakan tatasusunan juga perlu bertambah baik.
Sebagai contoh, penjana adalah alat baru. Pada mulanya kita hanya mempunyai tatasusunan, dan kemudian kita mendapat keupayaan untuk menentukan struktur array kelas kita sendiri (dipanggil iTerators). Tetapi sejak Php 5.5, kita dapat dengan cepat membuat struktur iterator kelas yang dipanggil penjana.
Kami akan melihat beberapa bidang di mana penjana boleh digunakan dan meneroka beberapa isu yang perlu diberi perhatian apabila menggunakan penjana. Akhirnya, kita akan belajar perpustakaan hebat yang dicipta oleh Nikita Popov yang berbakat.
Kod sampel boleh didapati di https://github.com/sitePoint-editors/generators-and-iter.
mata utama
array_filter
, yang memerlukan alat lain seperti Nikic/ITER untuk mengendalikan data tersebut. array_map
Soalan
Katakan anda mempunyai banyak data relasi dan ingin melakukan beberapa preloading. Mungkin data yang dipisahkan koma, anda perlu memuatkan setiap jenis data dan mengumpulkannya bersama-sama.anda boleh memulakan dengan kod mudah berikut:
<code class="language-php">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") );</code>anda kemudian boleh cuba untuk menggabungkan unsur -unsur yang berkaitan dengan fungsi berulang atau lebih tinggi:
<code class="language-php">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);</code>kelihatan baik, bukan? Jadi, apa yang berlaku apabila kita mempunyai sejumlah besar fail CSV untuk menghuraikan? Mari kita menganalisis penggunaan memori sedikit ...
<code class="language-php">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());</code>(kod sampel mengandungi
, yang boleh anda gunakan untuk membuat fail CSV ini ...) generate.php
Penjana datang untuk menyelamatkan!
Satu cara untuk memperbaiki masalah ini ialah menggunakan penjana. Jika anda tidak biasa dengan mereka, kini adalah masa yang baik untuk mengetahui lebih lanjut.Penjana membolehkan anda memuatkan sejumlah kecil jumlah data sekaligus. Anda tidak perlu berbuat banyak dengan penjana:
<code class="language-php">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") );</code>
Jika anda melangkah melalui data CSV, anda akan melihat bahawa jumlah memori yang diperlukan akan dikurangkan dengan segera:
<code class="language-php">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);</code>
Jika anda telah melihat megabytes penggunaan memori sebelum ini, anda kini akan melihat kilobytes. Ini adalah peningkatan yang besar, tetapi bukan tanpa masalahnya.
Pertama sekali, array_filter
dan array_map
tidak berfungsi dengan penjana. Anda mesti mencari alat lain untuk memproses jenis data ini. Berikut adalah alat yang boleh anda cuba!
<code class="language-php">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());</code>
Perpustakaan ini memperkenalkan beberapa fungsi yang boleh digunakan dengan iterator dan penjana. Jadi bagaimana anda masih mendapat semua data yang relevan ini tanpa menyimpan sebarang data dalam ingatan?
<code class="language-php">function readCSVGenerator($file) { $handle = fopen($file, "r"); while (!feof($handle)) { yield fgetcsv($handle); } fclose($handle); }</code>
ini lebih mudah:
<code class="language-php">foreach (readCSVGenerator("posts.csv") as $post) { // 使用 $post 执行某些操作 } print "memory:" . formatBytes(memory_get_peak_usage());</code>
(membaca semula setiap sumber data tidak cekap setiap masa. Pertimbangkan menyimpan data berkaitan yang lebih kecil (seperti penulis dan kategori) dalam ingatan ...)
Perkara -perkara menarik lain
Untuk perpustakaan Nikic, ini hanyalah hujung gunung es! Pernah mahu meratakan array (atau iterator/penjana)?
<code class="language-bash">composer require nikic/iter</code>
anda boleh menggunakan fungsi seperti slice
dan take
untuk mengembalikan kepingan pembolehubah yang boleh diperolehi:
<code class="language-php">// ... (后续代码与原文类似,但使用iter库函数进行优化,此处省略以节省篇幅) ...</code>
Apabila anda menggunakan penjana lebih banyak, anda mungkin mendapati bahawa anda tidak perlu menggunakannya semula. Pertimbangkan contoh berikut:
<code class="language-php">// ... (使用iter库函数简化代码,此处省略以节省篇幅) ...</code>
Jika anda cuba menjalankan kod, anda akan melihat pengecualian yang mendorong: "tidak boleh melintasi penjana tertutup". Setiap fungsi iterator di perpustakaan ini mempunyai fungsi yang sepadan dengan swappable:
<code class="language-php">// ... (使用iter\flatten和iter\toArray函数的示例代码,此处省略以节省篇幅) ...</code>
Anda boleh menggunakan fungsi pemetaan ini beberapa kali. Anda juga boleh membuat penjana anda sendiri boleh dikembalikan:
<code class="language-php">// ... (使用iter\slice和iter\toArray函数的示例代码,此处省略以节省篇幅) ...</code>
Apa yang anda dapat dari itu adalah penjana yang boleh diguna semula!
Kesimpulan
Untuk setiap operasi gelung yang perlu anda pertimbangkan, penjana mungkin menjadi pilihan. Mereka juga berguna untuk perkara lain. Di mana ciri bahasa tidak mencukupi, Perpustakaan Nikic menyediakan sejumlah besar fungsi pesanan yang lebih tinggi.
adakah anda sudah menggunakan penjana? Adakah anda ingin melihat lebih banyak contoh tentang cara melaksanakannya dalam permohonan anda sendiri untuk beberapa peningkatan prestasi? Tolong beritahu kami!
(bahagian Soalan Lazim adalah serupa dengan teks asal, dan ditinggalkan di sini untuk menjimatkan ruang. Bahagian FAQ boleh dikekalkan secara pilihan atau disusun semula seperti yang diperlukan.)
Atas ialah kandungan terperinci Prestasi memori meningkat dengan penjana dan nikic/iter. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!