Newer Older
1 2
Eager Future2 is a Common Lisp library that provides composable
concurrency primitives that unify parallel and lazy evaluation, are
3 4
integrated with the Common Lisp condition system, and have automatic
resource management.
5 6 7 8 9 10 11 12 13

The basic unit of concurrency in Eager Future2 is the future, which is
a data type that acts as a proxy for the values of a no-argument
function (thunk) that is computed concurrently.

Eager Future2 provides several strategies for computing futures
(specified as keywords): :lazy (only computed when the future is asked
to yield its values), :speculative (may be computed when there is
processing capacity available), and :eager (computation begins as
soon as the future is created).
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57

A future is created by the pcall function, which takes a thunk to
compute, and optionally the computing strategy. The default computing
strategy is specified by *default-future-type*, which is :speculative
by default.

A future can be asked for its values with the yield function. The
function ready-to-yield? is a non-blocking way to check whether the
future is done computing. The function select takes a set of futures
and blocks until at least one future is ready to yield, returning that

Ongoing computation of a future can be aborted with the force
function, which takes the future and desired yield values and attempts
to install them in that future. If a future has already finished
computing, calling force on it will have no effect.

Error handling is done transparently (the same way as if the program
wasn't written to use futures) by proxying unhandled conditions and
available restarts across thread boundaries. An additional restart
called force-values is also offered, which simply calls force on the
future whose computation raised the error.

If a future is no longer referenced and gets garbage collected, any
ongoing computation associated with that future is aborted to release
underlying thread resources. This permits speculative computation to
be done without having to worry about manual resource management.

API documentation:

function pcall (thunk &optional (future-type *default-future-type*)) => future

  Given a function of no arguments, returns an object (called a
  future) that can later be used to retrieve the values computed by the

  future-type (by default the value of *default-future-type*) can either
  be :eager, :speculative, or :lazy. See the documentation of
  *default-future-type* for an explanation of the different future

  The function is called in an unspecified dynamic environment.

58 59 60 61 62 63 64 65
special variable *default-future-type*

  One of :eager, :speculative (default) or :lazy. If eager, any newly
  created futures start their computation immediately. If speculative,
  newly created futures are computed when thread pool threads are
  available, in FIFO future creation order. If lazy, newly created
  futures are not computed until asked to yield their values.

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
function ready-to-yield? (future) => nil or non-nil

  Returns non-nil if the future values have been computed, nil otherwise.

function yield (future) => value*

  Returns the computed values of the future.

  In case of a delayed future, computes the value of the future in the
  current thread.

  In case of a speculative future, if no other thread is computing the
  value of the future, computes the value in the current thread. If
  another thread is currently computing the value of the future, blocks
  until the value is available.

  In case of an eager future, blocks until the value is available.

function select (&rest futures) => future

  Returns the first future that is ready to yield.

function force (future &rest values) => nil

  If the future has not yet yielded a value, installs the given
  values as the yield-values of the future (stopping any ongoing
  computation of the future).

macro pexec (&body body) => future

Vladimir Sedach's avatar
Vladimir Sedach committed
  Shorthand for (pcall (lambda () ...))
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136

macro plet ((&rest bindings) &body body)

  Like LET, but all bindings are evaluated asynchronously.

function iterate-futures (proc futures) => nil

  Calls proc on each future in select order. Proc is a procedure that
  takes the currently yieldable future as its first argument, and the
  list of futures not yet processed as its second. Futures need to be
  yielded by proc - this is done so that proc can have control of error
  handling. The second argument is useful to for example be able to
  terminate remaining computations before a non-local control transfer.

function force-all (futures &rest values) => nil

  Calls force on all given future with values. Useful to stop
  remaining computations in for example iterate-futures.

macro pand (&rest exprs) => t or nil

  Evaluates expressions in parallel. If any expression yields nil,
  terminates all outstanding computations and returns nil. If all
  expressions yield a non-nil value, returns t.

macro por (&rest exprs) => nil or non-nil

  Evaluates expressions in parallel. Returns the value of the first
  expression that yields a non-nil value. If all expressions evaluate
  to nil, returns nil.

function select-timeout (timeout &rest futures) => future or nil

  Given a timeout (in seconds) and a set of futures, returns either
  nil if no futures are ready to yield when timeout seconds have
  elapsed, or the first yieldable future otherwise.

macro pfuncall (function &rest args) => result

  Evaluates args in parallel before funcalling the given function on them.
Vladimir Sedach's avatar
Vladimir Sedach committed
137 138 139 140

function touch (x) => value

  If x is a future, yields its value, otherwise returns x.