Fiber
Parallel asynchronous function calls.
Read the short concurrency model.
module Id : sig ... end
Fiber unique identifiers.
async f
is a fiber executing function f
in parallel to the caller. The caller scope will not return or raise before f
returns or raises. priority
is the execution priority, it defaults to the caller's priority. If only_main
is true
, the scheduler ensure that the function only gets excecuted on the main thread (defaults to false
).
val from_val : 'a -> 'a t
from_val v
is async (Fun.const v)
.
Note. Awaiting on fibers can always raise. If you want to guard against this, use the trapping combinators before awaiting them.
val await : 'a t -> 'a
await f
blocks until the asynchronous function of f
returns or raises.
val await_all : 'a t list -> 'a list
await_all fs
blocks until all fs
return or raise. Raises the leftmost exception if one of the fiber raises (including Cancelled
).
await_first fs
awaits the first, leftmost, fs
that returns or raises (including Cancelled
). The returned list (if any) is fs
, in the same order, without the fiber that returned. Raises Invalid_argument
if the list is empty.
await_either f0 f1
awaits the first, leftmost, fiber that returns or raises (including Cancelled
).
val poll : 'a t -> 'a option
poll f
is None
if f
is still running and it's return value or raise otherwise.
Picking is for selecting among competing computations.
val pick_first : 'a t list -> 'a
val cancel : 'a t -> unit
cancel f
marks the fiber f
and its current and future asynchronous function calls as being cancelled. If f
already returned this has no effect.
self_is_cancelled ()
is true
if the excecuting fiber is cancelled.
self_check_cancellation
raises Cancelled
if self_is_cancelled ()
is true
.
A few conveniences to protect from raising fibers. Avoids multiplying the number of await
functions.
trap_user_exn f
is f
but turns any exception except Cancelled
, Stack_overflow
, Out_of_memory
or Sys.Break
into Error _
.
trap_cancelled f
is f
but turns a Cancelled
exception into an option.
trap_any_exn
is f
but turns a Cancelled
exception into None
and any other exception except Stack_overflow
, Out_of_memory
, Sys.Break
, into Error _
.
val cancelled : 'a t -> bool
cancelled f
is true
iff f
is marked as cancelled.
module Handle : sig ... end
Existential fibers
block ~block ~cancel ~return
blocks the calling fiber (hereafter f
) on a blocking operation. The given functions are used as follows:
block f
is immediately invoked by the scheduler. This should register the blocking operation with an external entity reponsible for unblocking it when the operation result is available. If block f
raises, the exception is directly thrown into the fiber f
and not blocked.cancel f
is invoked in case f
gets cancelled while blocked on the operation. If true
is returned the scheduler unblocks f
and throws Cancelled
into f
. If false
is returned the operation remains blocked and return f
will be called once it is unblocked. If cancel f
raises the scheduler unblocks f
and throws the exception into f
.return f
is called to get the operation's value once it no longer blocks. This value is used to continue f
. If return f
raises the exception is thrown into f
.Take into account the following points:
Handle.t
does not even provide that).Cancelled
if their cancel
function is called. Either by returning true
or by raising in return
(Warning, if cancelled f
is true
in return
it does not mean that cancel
was called, it could have been blocked while being already cancelled).block
is guaranteed to be called by the domain executing the block. Other function may be called by other domains.block
is always called. If cancel
is called and returns true
or raises, return
is never called.Note that nothing will ever unblock unless you provide an adequate unblock
function to main
.
self_non_cancelling_blocks f
ensures in f ()
that blocking operations of the executing fiber do not get notified of cancellation if it gets cancelled (in other words, cancel
functions of block
s invoked by f
never get called).
Important. Unlike cancel
and self_cancel
which propagate to the asynchronous calls of a fiber. This does not. Making blocks non-cancelling may be paramount to a fiber's correctness, so it has to remain in control of it.
type unblock = poll:bool -> Handle.t option
The type for functions to unblock blocked fibers. These functions need to be given to main
.
An unblock
function is called by the scheduler as follows:
unblock ~poll:true
, the function should return a previously blocked fiber that no longer blocks, if any. The call must not block if there is no such fiber as there are other fibers that are willing to run.unblock ~poll:false
, the function must return a peviously blocked fiber that no longer blocks. If there is none, it can block for as long as it wishes as there are no fiber to run. If it returns None
it will be called again, which amounts to busy waiting.The function must not raise. If it does the exception is trapped and None
is returned.
val never_unblock : unblock
never_unblock
nevers unblocks anything. Only use this if you are philosophizing.
unblocks us
composes us
by calling them one after the other in circular order for fairness. FIXME. That doesn't work for poll:false
. See todo
.
val main : ?domains:int -> unblock:unblock -> (unit -> 'a) -> 'a
main f
creates a top level fiber with f
and runs it to completion.
unblock
is the function called by the scheduler to unblock. If you are never blocking but only awaiting you can use unblock_none
.domains
is the number of domains to use. Defaults to to the value specified in the environment variable AFFECT_DOMAIN_COUNT
or if unparseable to Domain.recommended_domain_count
.Just interpose main
on your main
function as follows:
let main () =
Fiber.main ~unblock:Funix.unblock @@ fun () ->
…
let () = if !Sys.interactive then () else exit (main ())
val pp : Stdlib.Format.formatter -> 'a t -> unit
pp ppf f
formats the fiber status f
for inspection.
val pp' :
(Stdlib.Format.formatter -> 'a -> unit) ->
Stdlib.Format.formatter ->
'a t ->
unit
pp' pp_v
is like pp
but uses pp_v
to format the value if available.
val pp_id : Stdlib.Format.formatter -> 'a t -> unit
pp_id ppf f
formats a short identifying header for f
val pp_value :
(Stdlib.Format.formatter -> 'a -> unit) ->
Stdlib.Format.formatter ->
'a t ->
unit
pp_value pp_v f
formats the fiber value of f
or a placeholder if its still running.
module Private : sig ... end
For devising your own scheduler.
There is no distinction between concurrency and parallelism. Fibers represent asynchronous function calls that execute in parallel to a calling function. We use the terms fiber and asynchronous function call interchangeably.
The model is as follow:
async
it does not return or raise before all these subcalls return or raise.await
which waits for an asynchronous function call to return or raise. Other than that, libraries provide suitable direct-style blocking functions that call block
underneath and an associated function to unblock
them that you specify for running your main
function.cancel
or self_cancel
.Cancelled
.Cancelled
.See also the design notes.