control.future
- Futures ¶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.
{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) ...))
{control.future
}
Returns a future that calls thunk in a separate thread.
(future expr) ≡ (make-future (lambda () expr))
{control.future
}
Returns #t
if obj is a future, #f
otherwise.
{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.
{control.future
}
Returns #t
if computation in future is finished,
#f
otherwise.