ぼちぼち日記

おそらくプロトコルネタを書いていることが多いんじゃないかと思います。

libuvで消費者ー生産者問題を解く(Condition Variableを使う)

1. 最近 libuv の開発が熱い

V8と並ぶNode.jsの屋台骨のlibuvですが、最近 libuv 周りの開発が熱いです。

まず libeio が削除され、ファイルI/O は libuv独自のスレッドプールを用いた管理方式に変わりました(unix: remove libeio)。 これまでファイルI/Oは libeio で同時スレッドが4つに限定されてされていましたが、今月末ぐらいに自動的にスレッド数をチューニングするように変える予定らしいです。 これが実装されると多数のファイルを同時に読み書きするような場合の性能がぐんと向上することでしょう。
そしてNodeのイベント管理の本丸、 libev の置き換え作業も進められています(unix: remove libev )。
どんな実装になるのか楽しみです。

2. Condition Variable のサポート

このようにいろいろ機能が整備しつつあるlibuvですが、最近スレッド周りのAPIで重要な機能(Condition Variable)が追加されました( Add support for condition variables on all platforms)。

Condition Variable (状態変数)は各スレッドの処理を同期させるために用いられるもので、マルチスレッド処理において非常に有用な機能です(参考: pthread日記(51) - Condition Variable overview)。 もともとWindows ではサポートされていない POSIX Thread の仕様のため libuv では実装されていませんでした。
今回、Strategies for Implementing POSIX Condition Variables on Win32 を使うことで、libuv の Windows 実装にポーティングされ、晴れて libuv で Condition Variable が利用できるようになりました。

3. libuvでConsumer-Producer Problem(消費者ー生産者問題)を実装する

このCondition Variable が大きく活用されるケースとして、Consumer-Producer Problem (消費者ー生産者問題)が挙げられます。マルチスレッド処理の競合状態でデッドロックが発生しないデザインパターンの一つです。
そこで新しく導入された libuv の Condition Variable の API を利用して、この Consumer-Producer Problem (消費者ー生産者問題)を実装してみました。

16個の消費者スレッドが1つの生産者スレッドが生成するデータを100回取り合うモデルです。
今回生産者と消費者の間でやり取りするバッファは1個の値を持つだけに制限しています。(libuv の実装でも用いられている ngx_queue を使っています。)

結果は下記の通り。
生産者がデータを1つ入れると32の消費者のうち1つの消費者が競合せずにデータを取り出していることがわかります。

=== start consumer-producer test ===
producer(2943925056) put value:0
consumer(3027852096) gets value:0
producer(2943925056) put value:1
consumer(3036244800) gets value:1
producer(2943925056) put value:2
consumer(3019459392) gets value:2
(中略)
consumer(3069815616) gets value:1597
producer(2943925056) put value:1598
consumer(3078208320) gets value:1598
producer(2943925056) put value:1599
consumer(3078208320) gets value:1599
*** finsihed_consumers=16 ***
=== end consumer-producer test ===

これを使うと libuv のマルチスレッド処理が格段に幅が広がります。

Node.js のマルチスレッド実装(isolate 機能)はその複雑さから開発が中止になりましたが、今後環境が整備されてくるともしかしてたら将来的に復活もあるかもしれません。

ちなみに、

これテスト化して本家に取り込んでもらいました(test: add consumer-producer test for condvar)。いつもコードを丁寧に添削してくれるベンに感謝です。