以前「PHP7.4からのマルチスレッド」という記事を書きましたが、内容が薄すぎたのでもう少し紹介していきたいと思います。コードは全く載せていないのでサンプルはParallelのテストコードを見てください。
なお、 PHPにおけるマルチスレッドはCLI限定となります。(CLI限定なのはpthreadsだけでした) マルチプロセスを実現するpcntlではwebサーバで使用することを非推奨としていますが、pthreadsやparallelではコンパイルから拒否されます。
拡張モジュール
krakjoe氏が開発しているParallelを使用します。
https://github.com/krakjoe/parallel
マルチスレッドモデル
ParallelはGo言語のgoroutineに大きく影響を受けています。
https://www.php.net/manual/ja/philosophy.parallel.php
parallel\Runtime
RuntimeはpthreadsのWorkerにかなり近いです。
インスタンスが生成されたときにスレッドが起動し、破棄されるときまたはclose()やkill()が呼ばれたときにスレッドをシャットダウンします。run()を呼ぶと引数で指定したクロージャが__スケジュール__され、即座にFutureを返します。スケジュールされたクロージャは順次実行されます。
parallel\Future
何の変哲もないFutureパターンの実装です。
cancel()によりスケジュールされたタスクを中断させることができます。
parallel\Channel
仕様はgoroutineのチャンネルとほぼ同じです。Parallelではチャンネルに文字列で名前を設定することができます。匿名でも勝手に名前が付きます。open()によって好きな場所からチャンネル名を指定して特定のチャンネルを得ることができます。また、バッファのサイズを無制限にできます。PHPっぽさが感じられますね。
parallel\Events
複数のFutureやChannelを束ねてデータの受信をイベントとするイベントストリームを提供します。また、poll()でイベントを受け取れますが、データの送信元となったFutureやChannelはイベントストリームから削除されます。継続して同じChannelからのイベントを受け取りたい場合、Event\Type::ReadであろうとEvent\Type::WriteであろうとaddChannel()によって再登録が必要です。
parallel\Events\Input
複数のチャンネルにそれぞれ指定したデータを送信する操作を定義することができます。1つのチャンネルに複数のデータを送信することはできません。Eventsにセットすることで、ストリームが動き始めたタイミングで各チャンネルにデータを送信され、Event\Type::Writeのイベントが発生します。また、Inputに設定した項目は送信されたものから削除されていきます。
parallel\Sync
昔ながらの低レベルの実装をしたければこれを使いましょう。ほとんどのケースではChannelの方が優れているとのこと。
ParallelではCLIは要求されないらしい
pthreadsでもParallelでもコンパイル時にZTSは要求されます。
pthreads: https://github.com/krakjoe/pthreads/blob/master/config.m4#L11-L16
Parallel: https://github.com/krakjoe/parallel/blob/develop/config.m4#L14-L19
pthreadsでは実行時(PHP_MINIT_FUNCTION)にcli, phpdbg, homegearのいずれかであることをチェックします。
https://github.com/krakjoe/pthreads/blob/master/php_pthreads.c#L93-L113
https://github.com/krakjoe/pthreads/blob/master/php_pthreads.c#L251-L255
Parallelではそういった制限がありません。