control.future - Future ¶futureは並行計算を簡単にする構造です。
指定された式の計算を並行して行います。計算結果はfuture-getで取り出すことができます。
futureはMultiLispで実装されました。
MultiLispのfutureは暗黙的、つまり計算が終わるとその結果に自動的に置き換わるものでした。
RacketとGuileはライブラリでfutureを提供していますが、
結果の取り出しをtouchと呼んでいます。touchという名前は一般的にすぎるので、
Gaucheではfuture-getと呼ぶことにしました。
{control.future}
exprを別スレッドで計算するfutureオブジェクトを返します。
exprの結果はfuture-getで取り出せます。
(exprは多値を生成することもできます)。
exprはfuture式と同じ環境で評価されます。
ただし、exprが捕捉されない例外を投げた場合は、future-getが呼ばれるまで
その例外の配送は遅延されます。
次の例では、HTTPアクセスを他の計算と並行して走らせて、後で結果を取り出しています。
(use control.future)
(use rfc.http)
(let1 f (future (http-get "example.com" "/"))
... some computation ...
(receive (code headers body) (future-get f)
...))
{control.future}
thunkを別スレッドで呼ぶfutureを返します。
(future expr) ≡ (make-future (lambda () expr))
{control.future}
objがfutureなら#tを、そうでなければ#tを返します。
{control.future}
future引数はfutureを生成する式でなければなりません。
このマクロはその結果を取り出します。
futureの結果が既に求まっていれば、この手続きはただちにそれを返します。
まだ計算中であった場合は、デフォルトでこの手続きは計算が終わるまでブロックします。
待つ時間の上限をtimeout引数で指定することもできます。
timeoutが#f(デフォルト)なら無制限に待ち、
非負実数ならその秒数だけ待ち、<time>オブジェクトならそれで指定される
絶対時間まで待ちます。タイムアウトが起きた場合はtimeout-exprが
future-getの呼び出しの末尾コンテクストで評価されます。
timeout-exprが省略された場合のデフォルトは#fです。
これはマクロなので、多値を生成する式をtimeout-exprに与えることが できます。多値を生成するfutureに対するタイムアウト値を指定するのに便利です。
(define f (future (sys-sleep 1) (values 'a 'b 'c)))
(future-get f 0.1 (values 'x 'y 'z))
⇒ returns 3 values: x y z
futureの計算中に捕捉されない例外が投げられた場合、それはfuture-getを呼んだ時点で
future-getの動的環境で再び投げられます。
そのfutureにもう一度future-getを呼んだ場合の動作は未定義です
(現在は、二度目以降は例外を投げることなく#<undef>が返されますが、
将来変わる可能性があります)。
註: Gauche 0.9.15までのfuture-getは手続きでしたが、
多値のタイムアウト値を自然に扱うために、マクロに変更されました。
互換性のために、future-getは実際にはハイブリッドマクロとして
定義されています (ハイブリッドマクロ参照)。
future-getを高階手続きとして引数に渡している次のようなコードは
そのまま動きます:
(map future-get (list (future 1) (future 2))) ⇒ (1 2)
0.9.15以前のコードとの唯一の目に見える違いは、いつtimeout-exprが
評価されるかです。以前のリリースでは、それはfuture-getの呼び出し時に
評価されていましたが、現在のリリースではタイムアウトが起きた時点で評価されます。
このタイミングに依存している既存のコードがあれば、アップデートが必要です。
{control.future}
futureの計算が終わっていれば#tを、そうでなければ#fを返します。