For Development HEAD DRAFTSearch (procedure/syntax/module):

12.7 control.future - Futures

Module: control.future

A future is a simple construct for concurrent computation.

It encloses an expression, and compute its value concurrently. The result of computation can be retrieved later with future-get.

Futures are introduced in MultiLisp, in which retrieval of the computed value is implicit—a future is substituted with the result automatically. Racket and Guile have futures as a library, though the primitive to retrieve the result is called touch. We avoided to use the name since touch is too generic.

Macro: future expr

{control.future} Returns a future object, which runs the computation of expr in a separate thread. The result(s) of expr can be retrieved by future-get. Note that expr can yield multiple values.

The expr is evaluated in the same environment as future appears, though if an exception raised within expr is not caught, its delivery is delayed until you call future-get.

The following example runs HTTP access concurrently with other computation, and retrieves the result later.

(use control.future)
(use rfc.http)

(let1 f (future (http-get "example.com" "/"))
  ... some computation ...
  (receive (code headers body) (future-get f)
    ...))
Function: make-future thunk

{control.future} Returns a future that calls thunk in a separate thread.

(future expr) ≡ (make-future (lambda () expr))
Function: future? obj

{control.future} Returns #t if obj is a future, #f otherwise.

Macro: future-get future :optional timeout timeout-expr

{control.future} The future argument must be an expression that yields a future. This macro retrieves its the result(s).

If the result of future is already available, it is returned immediately. If future is still computing, future-get blocks until the result is ready by default. You can limit how long you will wait by timeout argument, which can be #f (default, no timeout), a nonnegative real numebr (relative time in seconds), or a <time> object (absolute timepoint). If the timeout reaches before the result is available, timeout-expr is evaluated in the tail context of the call of future-get. When timeout-expr is omitted, #f is assumed.

Since this is a macro, you can put multi-value yielding expression in timeout-expr. It is convenient to give the timeout values for a multi-value yielding 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

If an uncaught exception is raised during computation in the future, it is kept and reraised from future-get. It is handled in the dynamic environment of future-get (not the one in the original future call). If you call future-get again on such future, the effect is undefined (currently it returns #<undef> without raising an exception, but it may change in future).

NB: Up to Gauche 0.9.15, future-get was a procedure. We changed it to a macro to allow multiple timeout values naturally.

For the backward compatibility, future-get is actually defined as a hybrid macro (see Hybrid macros), so the existing code that passes future-get as a higher-order function still works:

(map future-get (list (future 1) (future 2))) ⇒ (1 2)

The only visible change from 0.9.15 code is when timeout-expr is evaluated: In the previous releases, it was evaluated when you call future-get; in the current releases, it is evaluated when the timeout occurs. If the exsting code relies on the timing, it needs to be updated.

Function: future-done? future

{control.future} Returns #t if computation in future is finished, #f otherwise.



For Development HEAD DRAFTSearch (procedure/syntax/module):
DRAFT