For example, the following code runs in about 1 second because both sleep/1 calls happen in parallel. When foo/0 unifies L, it blocks until silly/1 has finished.
silly(L) :- sleep(1), L = [a,b]. foo :- spawn(silly(L)), sleep(1), L=[A,B], % blocks, if necessary writeln(A-B).
If Goal produces multiple solutions, they're iterated when
backtracking over the unification (L=[A,B]
above). If Goal fails
or throws an exception, the calling thread sees it at the unification
point.
lazy
thread policy.
lazy/1 can be helpful when complicated or expensive goals are only needed in some code paths but duplicating those goals is too verbose. It can be an alternative to creating a new, named predicate. For example,
foo(Xs) :- lazy(i_am_slow(a,B,[c(C),d(d),e(etc)])), % complicated ( day_of_week(tuesday) -> append(B,C,Xs) ; phase_of_moon(full) -> append(C,B,Xs) ; true -> % i_am_slow/3 not executed in this code path Xs = [hi] ).
Options are as follows:
ephemeral
(default), create a new thread in which to call
goal. If lazy
, only execute Goal when await/1 is called; no
background threads are used.await/1 strives to have the same determinism as the original Goal passed to async/3. If that goal fails, await/1 fails. If that goal throws an exception, so does await/1. If that goal produces many solutions, so does await/1 on backtracking.