PHPの代表的なIterableとして、配列、Iterator、Generatorの3つの単純なループについてベンチマークしてみました。
前提条件
- PHP8.3.7
- Ubuntu22.04.3(WSL2)
- ベンチマークツール: macocci7/php-benchmark
使用したIterator
<?php
namespace MyLoop;
class MyIteratorAggregate implements \IteratorAggregate
{
private array $items;
public function __construct(array $items = [])
{
$this->items = $items;
}
public function getIterator(): \Traversable
{
return new \ArrayIterator($this->items);
}
}
Iterable供給クラス
<?php
namespace MyLoop;
require_once __DIR__ . '/MyIteratorAggregate.php';
use MyLoop\MyIteratorAggregate;
class MyIterable
{
private int $count;
public function __construct(int $count)
{
$this->count = $count;
}
/**
* ゼロ埋めした配列を返す
*/
public function getArray()
{
return array_fill(0, $this->count, 0);
}
/**
* ゼロ埋めしたIteratorを返す
*/
public function getIterator()
{
return new MyIteratorAggregate(array_fill(0, $this->count, 0));
}
/**
* ゼロ埋めしたGeneratorを返す
*/
public function getGenerator()
{
foreach (array_fill(0, $this->count, 0) as $item) {
yield $item;
}
}
}
ベンチマークスクリプト
<?php
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/MyIterable.php';
use Macocci7\PhpBenchmark\Benchmark;
use MyLoop\MyIterable;
$sort = true; // 結果のソート:する(実行時間)
$desc = false; // 結果ソート順:asc(実行時間昇順)
// 各Iterable共通の要素数
$count = 1000000; // ひゃくまん
// Iterable供給クラスのインスタンス生成
$iterable = new MyIterable($count);
// ベンチマーク対象のコールバック
$callbacks = [
// 配列をループ
'array' => function ($iterable) {
foreach ($iterable->getArray() as $item) {
++$item; // とりあえず処理
}
},
// Iteratorをループ
'Iterator' => function ($iterable) {
foreach ($iterable->getIterator() as $item) {
++$item; // とりあえず処理
}
},
// Generatorをループ
'Generator' => function ($iterable) {
foreach ($iterable->getGenerator() as $item) {
++$item; // とりあえず処理
}
},
];
// ベンチマーク実行
$result = Benchmark::codes(
callbacks: $callbacks, // コールバック
params: [$iterable], // 各コールバック共通引数
iteration: 1, // 各コールバック共通実行回数
sort: $sort, // 結果のソート:する(実行時間)
desc: $desc, // 結果ソート順:asc(実行時間昇順)
);
// ベンチマーク結果出力
Benchmark::stdout($result);
ベンチマーク実行
5回実行した結果です。
▼1回目
1: array => Time: 0.057756 sec
2: Iterator => Time: 0.159190 sec
3: Generator => Time: 0.587436 sec
▼2回目
1: array => Time: 0.070172 sec
2: Iterator => Time: 0.169492 sec
3: Generator => Time: 0.588523 sec
▼3回目
1: array => Time: 0.059871 sec
2: Iterator => Time: 0.117324 sec
3: Generator => Time: 0.738056 sec
▼4回目
1: array => Time: 0.095205 sec
2: Iterator => Time: 0.122262 sec
3: Generator => Time: 0.386092 sec
▼5回目
1: array => Time: 0.068467 sec
2: Iterator => Time: 0.142236 sec
3: Generator => Time: 0.628917 sec
まとめ
顕著な結果が出ましたね。
▶実行時間: array < Iterator < Generator
Iterator は array の2倍~3倍程度
Generator は Iterator の3倍~5倍程度
といったところでしょうか。
コメント