Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

[PHPカンファレンス北海道2024 全然野菜]PHPとLaravelで使える ジェネレータ...

Z.O.E.
January 11, 2024
87

[PHPカンファレンス北海道2024 全然野菜]PHPとLaravelで使える ジェネレータを使った大量データ処理のパフォーマンス改善

Z.O.E.

January 11, 2024
Tweet

More Decks by Z.O.E.

Transcript

  1. X(旧twitter): @for__3 #phpcondo_yasai 3 株式会社ウィルゲート 9年⽬ VPoE やってること - 教育/採⽤/PM/SRE/インフラ

    興味あること - オブザーバビリティ/⾃動化/開発⽣産性/PHP 執筆 - 【第3回】Dockerで実現! 効率的で⾼速な開発環境 ……makeコマンド⼀発でできる! - 【最終回】パフォーマンスチューニングをしよう ……PHP 8でXdebugとWebgrindを使ってプロファイ リング 池添 誠(いけぞえ まこと)
  2. X(旧twitter): @for__3 #phpcondo_yasai 任意の個数の配列を作る関数を考える 10 function makeList($n) { $list =

    []; for ($i = 0; $i <= $n; $i++) { $list[] = $i; } return $list; } echo "array:"; $array = makeList($limit); foreach ($array as $item) { echo $item . ','; } 出力> array:0,1,2,3,4,5,6,7,8,9,10,11,12,1 3,14,15,16,17,18, 19,20,21,22,23,24,25,26,27,28,29,30, 31,32,33,34,35,36, 37,38,39,40,41,42,43,44,45,46,47,48, 49,50,51,52,53,54, 55,56,57,58,59,60,61,62,63,64,65,66, 67,68,69,70,71,72, 73,74,75,76,77,78,79,80,81,82,83,84, 85,86,87,88,89,90, 91,92,93,94,95,96,97,98,99,100,
  3. X(旧twitter): @for__3 #phpcondo_yasai generator版 11 function makeGen($n) { for ($i

    = 0; $i <= $n; $i++) { yield $i; } } echo "generator:"; $gen = makeGen($limit); foreach ($gen as $item) { echo $item . ','; } 出力> generator:0,1,2,3,4,5,6,7,8,9,10,11, 12,13,14,15,16,17,18,19,20,21,22,23, 24,25,26,27,28,29,30,31,32,33,34,35, 36,37,38,39,40,41,42,43,44,45,46,47, 48,49,50,51,52,53,54,55,56,57,58,59, 60,61,62,63,64,65,66,67,68,69,70,71, 72,73,74,75,76,77,78,79,80,81,82,83, 84,85,86,87,88,89,90,91,92,93,94,95, 96,97,98,99,100,
  4. X(旧twitter): @for__3 #phpcondo_yasai ⽐較 12 function makeGen($n) { for ($i

    = 0; $i <= $n; $i++) { yield $i; } } echo "generator:"; $gen = makeGen($limit); foreach ($gen as $item) { echo $item . ','; } function makeList($n) { $list = []; for ($i = 0; $i <= $n; $i++) { $list[] = $i; } return $list; } echo "array:"; $array = makeList($limit); foreach ($array as $item) { echo $item . ','; } 配列版 generator版
  5. X(旧twitter): @for__3 #phpcondo_yasai ⽐較 13 function makeGen($n) { for ($i

    = 0; $i <= $n; $i++) { yield $i; } } function makeList($n) { $list = []; for ($i = 0; $i <= $n; $i++) { $list[] = $i; } return $list; } 返却⽤の配列に⼊れて返す 値をそのままyieldで返す 配列版 generator版
  6. X(旧twitter): @for__3 #phpcondo_yasai ⽐較 14 echo "generator:"; $gen = makeGen($limit);

    foreach ($gen as $item) { echo $item . ','; } echo "array:"; $array = makeList($limit); foreach ($array as $item) { echo $item . ','; } 配列版 generator版 配列から順次、値を取り出す generatorから順次yieldの値を取り出す
  7. X(旧twitter): @for__3 #phpcondo_yasai Collectionでごにょごにょする関数を考える 18 public function case1($collection ) {

    $counter = 0; $collection = $collection ->filter(function ($i) { return $i % 2 === 0; }) ->values() ->map(function ($i) { return $i * 3; }) ->chunk(3) ->each(function () use (&$counter) { $counter++; }) ->take(10) ->collect(); $this->info("each呼び出し回数: $counter"); return $collection ; } public function handle() { $number = $this->argument('number'); // Collection $collection = Collection::times($number); $this->startPerformance(); $this->case1($collection); $this->endPerformance(); $this->printPerformance(); }
  8. X(旧twitter): @for__3 #phpcondo_yasai Collectionでごにょごにょする関数を考える 19 public function case1($collection ) {

    $counter = 0; $collection = $collection ->filter(function ($i) { return $i % 2 === 0; }) ->values() ->map(function ($i) { return $i * 3; }) ->chunk(3) ->each(function () use (&$counter) { $counter++; }) ->take(10) ->collect(); $this->info("each呼び出し回数: $counter"); return $collection ; } public function handle() { $number = $this->argument('number'); // Collection $collection = Collection::times($number); $this->startPerformance(); $this->case1($collection); $this->endPerformance(); $this->printPerformance(); } 最終的に取得するデータは与える件数に依らず10件
  9. X(旧twitter): @for__3 #phpcondo_yasai 実⾏結果 20 docker-compose run --rm php php

    artisan measure:collection 1000 each呼び出し回数: 167 Time(ms): 0.301952 Memory: 736 b Peak Memory: 19.22 mb docker-compose run --rm php php artisan measure:collection 10000 each呼び出し回数: 1667 Time(ms): 1.145516 Memory: 24.72 kb Peak Memory: 20.33 mb docker-compose run --rm php php artisan measure:collection 100000 each呼び出し回数: 16667 Time(ms): 30.102493 Memory: 249.4 kb Peak Memory: 30.86 mb docker-compose run --rm php php artisan measure:collection 1000000 Symfony\Component\ErrorHandler\Error\FatalError Allowed memory size of 134217728 bytes exhausted (tried to allocate 4194312 bytes) at vendor/laravel/framework/src/Illuminate/Collections/Collection.php:1317
  10. X(旧twitter): @for__3 #phpcondo_yasai 実⾏結果 21 docker-compose run --rm php php

    artisan measure:collection 1000 each呼び出し回数: 167 Time(ms): 0.301952 Memory: 736 b Peak Memory: 19.22 mb docker-compose run --rm php php artisan measure:collection 10000 each呼び出し回数: 1667 Time(ms): 1.145516 Memory: 24.72 kb Peak Memory: 20.33 mb docker-compose run --rm php php artisan measure:collection 100000 each呼び出し回数: 16667 Time(ms): 30.102493 Memory: 249.4 kb Peak Memory: 30.86 mb docker-compose run --rm php php artisan measure:collection 1000000 Symfony\Component\ErrorHandler\Error\FatalError Allowed memory size of 134217728 bytes exhausted (tried to allocate 4194312 bytes) at vendor/laravel/framework/src/Illuminate/Collections/Collection.php:1317
  11. X(旧twitter): @for__3 #phpcondo_yasai 実⾏結果 22 docker-compose run --rm php php

    artisan measure:collection 1000 each呼び出し回数: 167 Time(ms): 0.301952 Memory: 736 b Peak Memory: 19.22 mb docker-compose run --rm php php artisan measure:collection 10000 each呼び出し回数: 1667 Time(ms): 1.145516 Memory: 24.72 kb Peak Memory: 20.33 mb docker-compose run --rm php php artisan measure:collection 100000 each呼び出し回数: 16667 Time(ms): 30.102493 Memory: 249.4 kb Peak Memory: 30.86 mb docker-compose run --rm php php artisan measure:collection 1000000 Symfony\Component\ErrorHandler\Error\FatalError Allowed memory size of 134217728 bytes exhausted (tried to allocate 4194312 bytes) at vendor/laravel/framework/src/Illuminate/Collections/Collection.php:1317 \件数が増えるごとにメモリと実⾏時間が増加/
  12. X(旧twitter): @for__3 #phpcondo_yasai LazyCollectionで実装してみる 24 public function case2($collection ) {

    $counter = 0; $collection = $collection ->filter(function ($i) { return $i % 2 === 0; }) ->values() ->map(function ($i) { return $i * 3; }) ->chunk(3) ->tapEach(function () use (&$counter) { $counter++; }) ->take(10) ->collect(); $this->info("each呼び出し回数: $counter"); return $collection ; } public function handle() { $number = $this->argument('number'); // Lazy Collection $collection = LazyCollection::times($number); $this->startPerformance(); $this->case2($collection); $this->endPerformance(); $this->printPerformance(); }
  13. X(旧twitter): @for__3 #phpcondo_yasai 実⾏結果 25 docker-compose run --rm php php

    artisan measure:lazy-collection 1000 each呼び出し回数: 10 Time(ms): 0.12558 Memory: 736 b Peak Memory: 19.54 mb docker-compose run --rm php php artisan measure:lazy-collection 10000 each呼び出し回数: 10 Time(ms): 0.116497 Memory: 736 b Peak Memory: 19.54 mb docker-compose run --rm php php artisan measure:lazy-collection 100000 each呼び出し回数: 10 Time(ms): 0.144288 Memory: 736 b Peak Memory: 19.54 mb docker-compose run --rm php php artisan measure:lazy-collection 1000000 each呼び出し回数: 10 Time(ms): 0.129414 Memory: 736 b Peak Memory: 19.54 mb \件数が増えてもメモリと実⾏時間が増加してない/