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
を返します。