ジェネレータこんにちは。最近、都内を離れると行くところ行くところ、雨に見舞われ、友人にも私が雨男という認識が何故か広まって困っています。先日は宮崎に帰省したところ、台風19号に直撃されて周りの友人から何故か非難を浴びるという理不尽を受けました。雨男の汚名返上できる方法をご存知の方はぜひ教えてください。PHP5.5で導入されたジェネレータさて、少し前の話題で恐縮ですが、PHPでは5.5からジェネレータという機能が新たに追加されました。同様の記事は巷に溢れかえっていますが、自分の学習と備忘録もかねて実装方法や特徴などをまとめてみました。ジェネレータとは、foreach文を使って連続した値や配列などの値の集合に対して順序に沿って処理(イテレーション)することができる新たな言語構造です。言葉だけでは理解しづらいため順に説明します。nlコマンドのような、パラメータで指定されたファイルから各行を読み込み行番号を付けて表示するプログラムを作る場合、次のように作ることができます。$line);}fclose($fp);配列を使った関数化プログラム1のようにファイルを読み込んで何か処理を加えるというプログラムでは、テキストファイルに関する他の処理でもファイルのオープンからファイル読み込みやファイルのクローズに至る処理が全く同じ処理になりやすいにもかかわらず、関数化しにくいという難点がありました。そこで汎用性を高めるために、実際にこのファイル読み込みだけを無理やり関数化してみます。$line);}上記のようにファイルの読み込みだけを行う関数を作成すると、どうしても配列などの巨大な変数にファイルのデータをいったんすべて取り込んで処理を行う必要がありました。するとどうしてもメモリを大きく消費してしまうというデメリットが残ってしまい、結局このような実装は避けられることが多かったのではないかと思います。Iteratorインターフェイスを使ったクラス化そこでPHPでは5.0からIteratorインターフェイスが提供されるようになり、foreach文にIteratorの実装クラスを渡せばファイルの読み込みなどもイテレーションができるようになりました。実際にプログラム2をIteratorインターフェイスの実装クラスに置き換えてみるとたとえば下記のような実装ができます。$line);}このようにIteratorインターフェイスを実装すれば、ファイルの読み込みをクラス化することができるようになり柔軟なプログラミングができるようになりました。currentの各メソッドも実装しなければならないという手間がかかってしまうというのが難点でした。このIteratorインターフェイスの実装では実行速度低下が著しいというデメリットもあります。結局のところ実装の手間や実行速度を妥協してでもクラス化するか、実効速度重視で関数化しないようにするかというジレンマを感じていた方も多いのではないでしょうか。5.5からジェネレータが導入されました!さっそくプログラム2をジェネレータを使った実装に置き換えてみましょう。$line);}プログラム3に比べてだいぶすっきりとして、プログラム2に近い実装になりました。プログラム2と大きくは変わっていませんが、8行目にyieldというキーワードが新たに増えています。ジェネレータではyieldキーワードを使って、変数の値を都度返却することができるようになりました。すべての読み出しが終わらなくても都度値が返却され、とメモリ上にすべてのデータを保持することもないため、メモリを効率よく使うことができるようになっています。実際に配列を使った実装(プログラム2)とIteratorインターフェイス実装(プログラム3)とジェネレータを使った実装(プログラム4)において、どの程度パフォーマンスに違いが出るのか、ざっくりと計測してみました。検証にあたってはプログラム2~4の一部を下記のように変更して測定しました。MB)を読み込ませました。14.04を載せて、PHPバージョンは5.5.9で検証しました。sec".PHP_EOL;結果は次のようになりました。秒プログラム2に比べてプログラム3やプログラム4はメモリの最大使用量が大きく減りました。配列に一旦保持しない分が減ったのではないかと推測できます。逆に経過時間(処理にかかった時間)については、プログラム3が極端に遅くなっており、プログラム2と4では、プログラム4の方が若干遅くなってしまいました。プログラム2と4の違いは配列に入れてまとめて返却するか、ジェネレータで都度返却するかの違いでしかありませんので、ジェネレータの方がオーバーヘッドが大きいのではないかと推測できます。(なお、10回以上実施しましたが、概ねこのような結果になり、経過時間ではジェネレータが、配列の実装を上回ることがありませんでした。)PHPの公式ページのNoteにも同様のパフォーマンス比較をされた方の投稿がありますが、やはりジェネレータの方が経過時間が長くかかる傾向にあるようです。パフォーマンスをまとめると下記のようになると思います。〇また違った検証をされた方がいらっしゃれば是非ご共有いただけると助かります。まとめPHPのジェネレータを使う上でのメリットを簡単にまとめてみました。イテレーションが必要な処理のメモリ効率の向上が期待できる関数化しづらかったイテレーション処理をシンプルに関数化できる今回の検証では特にジェネレータを使う上での大きなデメリットは見受けらず、積極的に使ってもただちに影響はなさそうです。PHP5.5以上をお使いの方で下位互換性を気にしない方は、ガンガン使っていきましょう!おまけちなみに、ジェネレータをvar_dumpしてみると下記のような結果が得られます。}内部でIteratorの実装クラスであるGeneratorオブジェクトを生成しているようです。Are青山のアドテク会社。アドネットワークやDSPを開発・運用。サーバを止めてみたよ。インターン:実業務体験編インターンでCTR予測をしましたSearchArchiveスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。