PHPにメッセージキューとそれを扱う糖衣構文を実装してみた (「PHPのすべらない話 #3」)
Goにできて、PHPにできないはずはない!というわけでやってしまいました。まあ、これにメッセージキューとメッセージスロットを足しただけなんですが。
<?php function sub($i, $ch) { for (;;) { $a = <- [$ch]; printf("%d:", $i); var_dump($a); } } $ch = thread_message_queue_create(); for ($i = 0; $i < 10; $i++) { thread_create('sub', $i, $ch); } $i = 0; for (;;) { [$ch] <- $i++; usleep(50000); } ?>
見て分かるように、
[$ch] <- $i++;
こんな感じにメッセージの送信を、
$msg = <- [$ch];
こんな感じにメッセージの受信を書くことができます。
パッチの当たった PHP は以下よりチェックアウトできます:
http://github.com/moriyoshi/php-src/tree/PHP_5_3-threading
無名関数をスレッドのエントリポイントにできない件については調査中です。
追記: 仕組みについて質問があったので。まず、PHP 本体への変更点についてですが、元の PHP に非互換な変更を加えているのは文法定義と、一部のマクロと関数名が衝突する部分のワークアラウンドのみで、あとは完全に拡張モジュールとして実装しています。言語ランタイムとしてはマルチスレッドをサポートしていない PHP でネイティブスレッド (pthread 等) を使うと、加減算などでアトミックオペレーションを保証しないといけない箇所が何カ所もあるため、修正作業が膨大になってしまうと思われます。そこで、getcontext(3) / setcontext(3) などを使ったコルーチンベースのユーザランドスレッディングを行うためのライブラリである pth を採用しました。PHP 自体はもともと pth をサポートしています。スレッド関連の関数の実装は ext/threading にあります。
追記2: スライドで「協調的マルチスレッド」という語を使っていましたが、これは実は「コルーチンベースのプリエンプティブなマルチスレッド」です。訂正します。