OCamlの並行プログラミング拡張 concurrent cell

OCaml-Nagoyaの会にて、id:osiireさんの concurrent cell (OCamlの並行プログラミングの拡張) の話を伺った。
当日の話について詳しくは ocaml-nagoya : ivarの必要性 より。

当初、問題そのものがちょっとよくわからなかったのだけど、要するに OCamlの標準ライブラリのマルチスレッド周りには、非同期通信(非同期な送信)のサポートが無い(らしい)のが問題であるように見える。

例えば ivar のページにある例 (を少し改変した):

open Event
let start_server () =
  let in_ch =
    new_channel ()
  in
  let rec loop () =
    let x,ret_ch = sync (receive in_ch) in
    loop (sync (send ret_ch (x * 2)))
  in
  ignore (Thread.create loop ());
  in_ch

というサーバースレッドは, (sync (send ret_ch (x * 2))) で計算結果を戻すのだけど、これは 同期的なので クライアントが受信するまではサーバー側がロックする. これは非常に不便.

すぐに思いつくworkaroundとして

Thread.create (fun _ -> sync (send ret_ch (x * 2))) ()

などとすれば サーバーは待たなくてよいのだけど、 クライアントが受信しない場合にこのスレッドは回収されない (らしい.そもそも マルチスレッドにおけるGCでどういう実現があるのか知らないのだけど、これくらいできないものかねえ).

で、id:osiireさんがOCamlに導入したのが ivar. これは非同期な書き込みが一度だけ可能なチャネル(とはちょっと違うか?). Concurrent MLの昔からあるものらしく,普通のチャネルと比べて効率的で,使われなかった場合にもGCで回収されるらしい. 上の例のように、別スレッドに出した要求の戻り値を取得するときの、ただ一度だけしか使わないチャネルとして使うのに有利だ.
π計算でもこういう通信パターンを linear typeで縛ったりする.

その他の話

上の話とは直接関係ないけれど,「同期ポイント」の話について.

let calc in_ch x =
  let ret_ch = new_channel () in
  wrap (send in_ch (x,ret_ch)) (fun () -> sync (receive ret_ch))

という calc : int channel -> int -> int event は 戻り値のイベント (型 int event) を select や choose で他のイベントと組み合わせた場合に、 最初のsendが成功すれば残りも実行される.
(ただ,この wrap : 'a event -> ('a -> 'b) -> 'b event には 副作用(というか同期)を伴うような関数を食わせないほうが良いような気がする)

let calc2 in_ch x =
  let ret_ch = new_channel () in
  guard (fun () ->
    sync (send in_ch (x,ret_ch));
    receive ret_ch)

という calc2 : int channel -> int -> int event は ... 戻り値のイベントを selectすると sendされ(ない場合もあるが),その後に起こる receive ret_ch のイベントが 他のイベントと併せて selectで選択される. (そして、サーバ側でsendを非同期にやらない場合は,必ずクライアント側でreceiveしなきゃなのでそもそもselectは使ってはいけない).

でも、同期ポイントが2個あり,calc関数をできるだけ一般的な形にしておきたい場合,

let calc3 in_ch x =
  let ret_ch = new_channel () in
  wrap (send in_ch (x,ret_ch)) (fun () -> (receive ret_ch))

として,この calc3 : int channel -> int -> (int event) event のように, (int event) event を返すようにするのが普通じゃないかなあと思う. こ うすれば,同期ポイントは2つでき,2つのポイントの依存関係も明確だ.