This module defines the common Either interface that is provided for all OCaml versions. For documentation of these functions, refer to the standard library.
This module defines the common Either interface that is provided for all OCaml versions. For documentation of these functions, refer to the standard library.
compare_and_set r seen v sets the new value of r to v only if its current value is physically equal to seen -- the comparison and the set occur atomically. Returns true if the comparison succeeded (so the set happened) and false otherwise.
compare_and_set r seen v sets the new value of r to v only if its current value is physically equal to seen -- the comparison and the set occur atomically. Returns true if the comparison succeeded (so the set happened) and false otherwise.
This queue is quite basic and will not behave well under heavy contention. However, it can be sufficient for many practical use cases.
NOTE: this queue will typically block the caller thread in case the operation (push/pop) cannot proceed. Be wary of deadlocks when using the queue from a pool when you expect the other end to also be produced/consumed from the same pool.
See discussion on Fut.wait_block for more details on deadlocks and how to mitigate the risk of running into them.
More scalable queues can be found in Lockfree (https://github.com/ocaml-multicore/lockfree/)
type'a t
Unbounded blocking queue.
This queue is thread-safe and will block when calling pop on it when it's empty.
Number of items currently in the queue. Note that pop might still block if this returns a non-zero number, since another thread might have consumed the items in the mean time.
try_pop q immediately pops the first element of q, if any, or returns None without blocking.
parameterforce_lock
if true, use Mutex.lock (which can block under contention); if false, use Mutex.try_lock, which might return None even in presence of an element if there's contention
transfer bq q2 transfers all items presently in bq into q2 in one atomic section, and clears bq. It blocks if no element is in bq.
This is useful to consume elements from the queue in batch. Create a Queue.t locally:
let dowork (work_queue: job Bb_queue.t) =
+Blocking_queue (moonpool.Moonpool.Blocking_queue)
Module Moonpool.Blocking_queue
A simple blocking queue.
This queue is quite basic and will not behave well under heavy contention. However, it can be sufficient for many practical use cases.
NOTE: this queue will typically block the caller thread in case the operation (push/pop) cannot proceed. Be wary of deadlocks when using the queue from a pool when you expect the other end to also be produced/consumed from the same pool.
See discussion on Fut.wait_block for more details on deadlocks and how to mitigate the risk of running into them.
More scalable queues can be found in Lockfree (https://github.com/ocaml-multicore/lockfree/)
type'a t
Unbounded blocking queue.
This queue is thread-safe and will block when calling pop on it when it's empty.
Number of items currently in the queue. Note that pop might still block if this returns a non-zero number, since another thread might have consumed the items in the mean time.
try_pop q immediately pops the first element of q, if any, or returns None without blocking.
parameterforce_lock
if true, use Mutex.lock (which can block under contention); if false, use Mutex.try_lock, which might return None even in presence of an element if there's contention
transfer bq q2 transfers all items presently in bq into q2 in one atomic section, and clears bq. It blocks if no element is in bq.
This is useful to consume elements from the queue in batch. Create a Queue.t locally:
let dowork (work_queue: job Bb_queue.t) =
(* local queue, not thread safe *)
let local_q = Queue.create() in
try
diff --git a/dev/moonpool/Moonpool/Bounded_queue/index.html b/dev/moonpool/Moonpool/Bounded_queue/index.html
index 29ca03a9..d9f05ab8 100644
--- a/dev/moonpool/Moonpool/Bounded_queue/index.html
+++ b/dev/moonpool/Moonpool/Bounded_queue/index.html
@@ -1,2 +1,2 @@
-Bounded_queue (moonpool.Moonpool.Bounded_queue)
Module Moonpool.Bounded_queue
A blocking queue of finite size.
This queue, while still using locks underneath (like the regular blocking queue) should be enough for usage under reasonable contention.
The bounded size is helpful whenever some form of backpressure is desirable: if the queue is used to communicate between producer(s) and consumer(s), the consumer(s) can limit the rate at which producer(s) send new work down their way. Whenever the queue is full, means that producer(s) will have to wait before pushing new work.
try_pop ~force_lock q tries to pop the first element, or returns None if no element is available or if it failed to acquire q.
parameterforce_lock
if true, use Mutex.lock (which can block under contention); if false, use Mutex.try_lock, which might return None even in presence of an element if there's contention.
to_gen q returns a (transient) sequence from the queue.
+Bounded_queue (moonpool.Moonpool.Bounded_queue)
Module Moonpool.Bounded_queue
A blocking queue of finite size.
This queue, while still using locks underneath (like the regular blocking queue) should be enough for usage under reasonable contention.
The bounded size is helpful whenever some form of backpressure is desirable: if the queue is used to communicate between producer(s) and consumer(s), the consumer(s) can limit the rate at which producer(s) send new work down their way. Whenever the queue is full, means that producer(s) will have to wait before pushing new work.
try_pop ~force_lock q tries to pop the first element, or returns None if no element is available or if it failed to acquire q.
parameterforce_lock
if true, use Mutex.lock (which can block under contention); if false, use Mutex.try_lock, which might return None even in presence of an element if there's contention.
Like pop, but blocks if an element is not available immediately. The precautions around blocking from inside a thread pool are the same as explained in Fut.wait_block.
Like pop, but blocks if an element is not available immediately. The precautions around blocking from inside a thread pool are the same as explained in Fut.wait_block.
NOTE: the runner should support DLA and Suspend_ on OCaml 5.x, so that Fork_join and other 5.x features work properly.
val k_cur_runner : t optionrefMoonpool__.Thread_local_storage_.key
Key that should be used by each runner to store itself in TLS on every thread it controls, so that tasks running on these threads can access the runner. This is necessary for get_current_runner to work.
FIFO: first-in, first-out. Basically tasks are put into a queue, and worker threads pull them out of the queue at the other end.
Since this uses a single blocking queue to manage tasks, it's very simple and reliable. The number of worker threads is fixed, but they are spread over several domains to enable parallelism.
This can be useful for latency-sensitive applications (e.g. as a pool of workers for network servers). Work-stealing pools might have higher throughput but they're very unfair to some tasks; by contrast, here, older tasks have priority over younger tasks.
If a runner is no longer needed, shutdown can be used to signal all worker threads in it to stop (after they finish their work), and wait for them to stop.
The threads are distributed across a fixed domain pool (whose size is determined by Domain.recommended_domain_count on OCaml 5, and simple the single runtime on OCaml 4).
run_wait_block pool f schedules f for later execution on the pool, like run_async. It then blocks the current thread until f() is done executing, and returns its result. If f() raises an exception, then run_wait_block pool f will raise it as well.
NOTE be careful with deadlocks (see notes in Fut.wait_block about the required discipline to avoid deadlocks).
FIFO: first-in, first-out. Basically tasks are put into a queue, and worker threads pull them out of the queue at the other end.
Since this uses a single blocking queue to manage tasks, it's very simple and reliable. The number of worker threads is fixed, but they are spread over several domains to enable parallelism.
This can be useful for latency-sensitive applications (e.g. as a pool of workers for network servers). Work-stealing pools might have higher throughput but they're very unfair to some tasks; by contrast, here, older tasks have priority over younger tasks.
If a runner is no longer needed, shutdown can be used to signal all worker threads in it to stop (after they finish their work), and wait for them to stop.
The threads are distributed across a fixed domain pool (whose size is determined by Domain.recommended_domain_count on OCaml 5, and simple the single runtime on OCaml 4).
run_async pool f schedules f for later execution on the runner in one of the threads. f() will run on one of the runner's worker threads/domains.
parametername
if provided and Trace is present in dependencies, a span will be created when the task starts, and will stop when the task is over. (since NEXT_RELEASE)
if the runner was shut down before run_async was called.
val run_wait_block : ?name:string ->t->(unit ->'a)->'a
run_wait_block pool f schedules f for later execution on the pool, like run_async. It then blocks the current thread until f() is done executing, and returns its result. If f() raises an exception, then run_wait_block pool f will raise it as well.
NOTE be careful with deadlocks (see notes in Fut.wait_block about the required discipline to avoid deadlocks).
NOTE These are only available on OCaml 5.0 and above.
since 0.3
val both : (unit ->'a)->(unit ->'b)->'a * 'b
both f g runs f() and g(), potentially in parallel, and returns their result when both are done. If any of f() and g() fails, then the whole computation fails.
This must be run from within the pool: for example, inside Pool.run or inside a Fut.spawn computation. This is because it relies on an effect handler to be installed.
since 0.3
NOTE this is only available on OCaml 5.
val both_ignore : (unit ->_)->(unit ->_)-> unit
Same as both f g |> ignore.
since 0.3
NOTE this is only available on OCaml 5.
val for_ : ?chunk_size:int ->int ->(int ->int -> unit)-> unit
for_ n f is the parallel version of for i=0 to n-1 do f i done.
f is called with parameters low and high and must use them like so:
for j = low to high do (* … actual work *) done
. If chunk_size=1 then low=high and the loop is not actually needed.
parameterchunk_size
controls the granularity of parallelism. The default chunk size is not specified. See all_array or all_list for more details.
Example:
let total_sum = Atomic.make 0
+Fork_join (moonpool.Moonpool.Fork_join)
Module Moonpool.Fork_join
Fork-join primitives.
NOTE These are only available on OCaml 5.0 and above.
since 0.3
val both : (unit ->'a)->(unit ->'b)->'a * 'b
both f g runs f() and g(), potentially in parallel, and returns their result when both are done. If any of f() and g() fails, then the whole computation fails.
This must be run from within the pool: for example, inside Pool.run or inside a Fut.spawn computation. This is because it relies on an effect handler to be installed.
since 0.3
NOTE this is only available on OCaml 5.
val both_ignore : (unit ->_)->(unit ->_)-> unit
Same as both f g |> ignore.
since 0.3
NOTE this is only available on OCaml 5.
val for_ : ?chunk_size:int ->int ->(int ->int -> unit)-> unit
for_ n f is the parallel version of for i=0 to n-1 do f i done.
f is called with parameters low and high and must use them like so:
for j = low to high do (* … actual work *) done
. If chunk_size=1 then low=high and the loop is not actually needed.
parameterchunk_size
controls the granularity of parallelism. The default chunk size is not specified. See all_array or all_list for more details.
A future of type 'a t represents the result of a computation that will yield a value of type 'a.
Typically, the computation is running on a thread pool Runner.t and will proceed on some worker. Once set, a future cannot change. It either succeeds (storing a Ok x with x: 'a), or fail (storing a Error (exn, bt) with an exception and the corresponding backtrace).
Combinators such as map and join_array can be used to produce futures from other futures (in a monadic way). Some combinators take a on argument to specify a runner on which the intermediate computation takes place; for example map ~on:pool ~f fut maps the value in fut using function f, applicatively; the call to f happens on the runner pool (once fut resolves successfully with a value).
bind ?on ~f fut returns a new future fut2 that resolves like the future f x if fut resolved with x; and fails with e if fut fails with e or f x raises e.
bind_reify_error ?on ~f fut returns a new future fut2 that resolves like the future f (Ok x) if fut resolved with x; and resolves like the future f (Error (exn, bt)) if fut fails with exn and backtrace bt.
choose a b succeeds Left x or Right y if a succeeds with x or b succeeds with y, or fails if both of them fails. If they both succeed, it is not specified which result is used.
choose_same a b succeeds with the value of one of a or b if they succeed, or fails if both fail. If they both succeed, it is not specified which result is used.
wait_list l waits for all futures in l to resolve. It discards the individual results of futures in l. It fails if any future fails.
val for_ : on:Runner.t->int ->(int -> unit)->unit t
for_ ~on n f runs f 0, f 1, …, f (n-1) on the runner, and returns a future that resolves when all the tasks have resolved, or fails as soon as one task has failed.
val for_array : on:Runner.t->'a array->(int ->'a-> unit)->unit t
for_array ~on arr f runs f 0 arr.(0), …, f (n-1) arr.(n-1) in the runner (where n = Array.length arr), and returns a future that resolves when all the tasks are done, or fails if any of them fails.
since 0.2
val for_list : on:Runner.t->'a list->('a-> unit)->unit t
for_list ~on l f is like for_array ~on (Array.of_list l) f.
wait_block fut blocks the current thread until fut is resolved, and returns its value.
NOTE: A word of warning: this will monopolize the calling thread until the future resolves. This can also easily cause deadlocks, if enough threads in a pool call wait_block on futures running on the same pool or a pool depending on it.
A good rule to avoid deadlocks is to run this from outside of any pool, or to have an acyclic order between pools where wait_block is only called from a pool on futures evaluated in a pool that comes lower in the hierarchy. If this rule is broken, it is possible for all threads in a pool to wait for futures that can only make progress on these same threads, hence the deadlock.
A future of type 'a t represents the result of a computation that will yield a value of type 'a.
Typically, the computation is running on a thread pool Runner.t and will proceed on some worker. Once set, a future cannot change. It either succeeds (storing a Ok x with x: 'a), or fail (storing a Error (exn, bt) with an exception and the corresponding backtrace).
Combinators such as map and join_array can be used to produce futures from other futures (in a monadic way). Some combinators take a on argument to specify a runner on which the intermediate computation takes place; for example map ~on:pool ~f fut maps the value in fut using function f, applicatively; the call to f happens on the runner pool (once fut resolves successfully with a value).
bind ?on ~f fut returns a new future fut2 that resolves like the future f x if fut resolved with x; and fails with e if fut fails with e or f x raises e.
bind_reify_error ?on ~f fut returns a new future fut2 that resolves like the future f (Ok x) if fut resolved with x; and resolves like the future f (Error (exn, bt)) if fut fails with exn and backtrace bt.
choose a b succeeds Left x or Right y if a succeeds with x or b succeeds with y, or fails if both of them fails. If they both succeed, it is not specified which result is used.
choose_same a b succeeds with the value of one of a or b if they succeed, or fails if both fail. If they both succeed, it is not specified which result is used.
wait_list l waits for all futures in l to resolve. It discards the individual results of futures in l. It fails if any future fails.
val for_ : on:Runner.t->int ->(int -> unit)->unit t
for_ ~on n f runs f 0, f 1, …, f (n-1) on the runner, and returns a future that resolves when all the tasks have resolved, or fails as soon as one task has failed.
val for_array : on:Runner.t->'a array->(int ->'a-> unit)->unit t
for_array ~on arr f runs f 0 arr.(0), …, f (n-1) arr.(n-1) in the runner (where n = Array.length arr), and returns a future that resolves when all the tasks are done, or fails if any of them fails.
since 0.2
val for_list : on:Runner.t->'a list->('a-> unit)->unit t
for_list ~on l f is like for_array ~on (Array.of_list l) f.
wait_block fut blocks the current thread until fut is resolved, and returns its value.
NOTE: A word of warning: this will monopolize the calling thread until the future resolves. This can also easily cause deadlocks, if enough threads in a pool call wait_block on futures running on the same pool or a pool depending on it.
A good rule to avoid deadlocks is to run this from outside of any pool, or to have an acyclic order between pools where wait_block is only called from a pool on futures evaluated in a pool that comes lower in the hierarchy. If this rule is broken, it is possible for all threads in a pool to wait for futures that can only make progress on these same threads, hence the deadlock.
NOTE: the runner should support DLA and Suspend_ on OCaml 5.x, so that Fork_join and other 5.x features work properly.
val k_cur_runner : t optionrefMoonpool__.Thread_local_storage_.key
Key that should be used by each runner to store itself in TLS on every thread it controls, so that tasks running on these threads can access the runner. This is necessary for get_current_runner to work.
Runner that runs tasks immediately in the caller thread.
Whenever a task is submitted to this runner via Runner.run_async r task, the task is run immediately in the caller thread as task(). There are no background threads, no resource, this is just a trivial implementation of the interface.
This can be useful when an implementation needs a runner, but there isn't enough work to justify starting an actual full thread pool.
Another situation is when threads cannot be used at all (e.g. because you plan to call Unix.fork later).
If a runner is no longer needed, shutdown can be used to signal all worker threads in it to stop (after they finish their work), and wait for them to stop.
The threads are distributed across a fixed domain pool (whose size is determined by Domain.recommended_domain_count on OCaml 5, and simple the single runtime on OCaml 4).
run_wait_block pool f schedules f for later execution on the pool, like run_async. It then blocks the current thread until f() is done executing, and returns its result. If f() raises an exception, then run_wait_block pool f will raise it as well.
NOTE be careful with deadlocks (see notes in Fut.wait_block about the required discipline to avoid deadlocks).
Runner that runs tasks immediately in the caller thread.
Whenever a task is submitted to this runner via Runner.run_async r task, the task is run immediately in the caller thread as task(). There are no background threads, no resource, this is just a trivial implementation of the interface.
This can be useful when an implementation needs a runner, but there isn't enough work to justify starting an actual full thread pool.
Another situation is when threads cannot be used at all (e.g. because you plan to call Unix.fork later).
If a runner is no longer needed, shutdown can be used to signal all worker threads in it to stop (after they finish their work), and wait for them to stop.
The threads are distributed across a fixed domain pool (whose size is determined by Domain.recommended_domain_count on OCaml 5, and simple the single runtime on OCaml 4).
run_async pool f schedules f for later execution on the runner in one of the threads. f() will run on one of the runner's worker threads/domains.
parametername
if provided and Trace is present in dependencies, a span will be created when the task starts, and will stop when the task is over. (since NEXT_RELEASE)
if the runner was shut down before run_async was called.
val run_wait_block : ?name:string ->t->(unit ->'a)->'a
run_wait_block pool f schedules f for later execution on the pool, like run_async. It then blocks the current thread until f() is done executing, and returns its result. If f() raises an exception, then run_wait_block pool f will raise it as well.
NOTE be careful with deadlocks (see notes in Fut.wait_block about the required discipline to avoid deadlocks).
with_ l f runs f x where x is the value protected with the lock l, in a critical section. If f x fails, with_lock l f fails too but the lock is released.
with_ l f runs f x where x is the value protected with the lock l, in a critical section. If f x fails, with_lock l f fails too but the lock is released.
NOTE: the runner should support DLA and Suspend_ on OCaml 5.x, so that Fork_join and other 5.x features work properly.
val k_cur_runner : t optionrefMoonpool__.Thread_local_storage_.key
Key that should be used by each runner to store itself in TLS on every thread it controls, so that tasks running on these threads can access the runner. This is necessary for get_current_runner to work.
This provides an abstraction for running tasks in the background, which is implemented by various thread pools.
since 0.3
type task = unit -> unit
type t
A runner.
If a runner is no longer needed, shutdown can be used to signal all worker threads in it to stop (after they finish their work), and wait for them to stop.
The threads are distributed across a fixed domain pool (whose size is determined by Domain.recommended_domain_count on OCaml 5, and simple the single runtime on OCaml 4).
run_wait_block pool f schedules f for later execution on the pool, like run_async. It then blocks the current thread until f() is done executing, and returns its result. If f() raises an exception, then run_wait_block pool f will raise it as well.
NOTE be careful with deadlocks (see notes in Fut.wait_block about the required discipline to avoid deadlocks).
Access the current runner. This returns Some r if the call happens on a thread that belongs in a runner.
since 0.5
+Runner (moonpool.Moonpool.Runner)
Module Moonpool.Runner
Interface for runners.
This provides an abstraction for running tasks in the background, which is implemented by various thread pools.
since 0.3
type task = unit -> unit
type t
A runner.
If a runner is no longer needed, shutdown can be used to signal all worker threads in it to stop (after they finish their work), and wait for them to stop.
The threads are distributed across a fixed domain pool (whose size is determined by Domain.recommended_domain_count on OCaml 5, and simple the single runtime on OCaml 4).
run_async pool f schedules f for later execution on the runner in one of the threads. f() will run on one of the runner's worker threads/domains.
parametername
if provided and Trace is present in dependencies, a span will be created when the task starts, and will stop when the task is over. (since NEXT_RELEASE)
if the runner was shut down before run_async was called.
val run_wait_block : ?name:string ->t->(unit ->'a)->'a
run_wait_block pool f schedules f for later execution on the pool, like run_async. It then blocks the current thread until f() is done executing, and returns its result. If f() raises an exception, then run_wait_block pool f will raise it as well.
NOTE be careful with deadlocks (see notes in Fut.wait_block about the required discipline to avoid deadlocks).
NOTE: the runner should support DLA and Suspend_ on OCaml 5.x, so that Fork_join and other 5.x features work properly.
val k_cur_runner : t optionrefMoonpool__.Thread_local_storage_.key
Key that should be used by each runner to store itself in TLS on every thread it controls, so that tasks running on these threads can access the runner. This is necessary for get_current_runner to work.
A pool of threads with a worker-stealing scheduler. The pool contains a fixed number of threads that wait for work items to come, process these, and loop.
This is good for CPU-intensive tasks that feature a lot of small tasks. Note that tasks will not always be processed in the order they are scheduled, so this is not great for workloads where the latency of individual tasks matter (for that see Fifo_pool).
If a pool is no longer needed, shutdown can be used to signal all threads in it to stop (after they finish their work), and wait for them to stop.
The threads are distributed across a fixed domain pool (whose size is determined by Domain.recommended_domain_count on OCaml 5, and simply the single runtime on OCaml 4).
If a runner is no longer needed, shutdown can be used to signal all worker threads in it to stop (after they finish their work), and wait for them to stop.
The threads are distributed across a fixed domain pool (whose size is determined by Domain.recommended_domain_count on OCaml 5, and simple the single runtime on OCaml 4).
run_wait_block pool f schedules f for later execution on the pool, like run_async. It then blocks the current thread until f() is done executing, and returns its result. If f() raises an exception, then run_wait_block pool f will raise it as well.
NOTE be careful with deadlocks (see notes in Fut.wait_block about the required discipline to avoid deadlocks).
A pool of threads with a worker-stealing scheduler. The pool contains a fixed number of threads that wait for work items to come, process these, and loop.
This is good for CPU-intensive tasks that feature a lot of small tasks. Note that tasks will not always be processed in the order they are scheduled, so this is not great for workloads where the latency of individual tasks matter (for that see Fifo_pool).
If a pool is no longer needed, shutdown can be used to signal all threads in it to stop (after they finish their work), and wait for them to stop.
The threads are distributed across a fixed domain pool (whose size is determined by Domain.recommended_domain_count on OCaml 5, and simply the single runtime on OCaml 4).
If a runner is no longer needed, shutdown can be used to signal all worker threads in it to stop (after they finish their work), and wait for them to stop.
The threads are distributed across a fixed domain pool (whose size is determined by Domain.recommended_domain_count on OCaml 5, and simple the single runtime on OCaml 4).
run_async pool f schedules f for later execution on the runner in one of the threads. f() will run on one of the runner's worker threads/domains.
parametername
if provided and Trace is present in dependencies, a span will be created when the task starts, and will stop when the task is over. (since NEXT_RELEASE)
if the runner was shut down before run_async was called.
val run_wait_block : ?name:string ->t->(unit ->'a)->'a
run_wait_block pool f schedules f for later execution on the pool, like run_async. It then blocks the current thread until f() is done executing, and returns its result. If f() raises an exception, then run_wait_block pool f will raise it as well.
NOTE be careful with deadlocks (see notes in Fut.wait_block about the required discipline to avoid deadlocks).
called at the beginning of each new thread in the pool.
parameternum_threads
size of the pool, ie. number of worker threads. It will be at least 1 internally, so 0 or negative values make no sense. The default is Domain.recommended_domain_count(), ie one worker thread per CPU core. On OCaml 4 the default is 4 (since there is only one domain).
parameteron_exit_thread
called at the end of each thread in the pool
parameteraround_task
a pair of before, after, where before pool is called before a task is processed, on the worker thread about to run it, and returns x; and after pool x is called by the same thread after the task is over. (since 0.2)
called at the beginning of each new thread in the pool.
parameternum_threads
size of the pool, ie. number of worker threads. It will be at least 1 internally, so 0 or negative values make no sense. The default is Domain.recommended_domain_count(), ie one worker thread per CPU core. On OCaml 4 the default is 4 (since there is only one domain).
parameteron_exit_thread
called at the end of each thread in the pool
parameteraround_task
a pair of before, after, where before pool is called before a task is processed, on the worker thread about to run it, and returns x; and after pool x is called by the same thread after the task is over. (since 0.2)
A pool within a bigger pool (ie the ocean). Here, we're talking about pools of Thread.t that are dispatched over several Domain.t to enable parallelism.
We provide several implementations of pools with distinct scheduling strategies, alongside some concurrency primitives such as guarding locks (Lock.t) and futures (Fut.t).
Default pool. Please explicitly pick an implementation instead.
val start_thread_on_some_domain : ('a-> unit)->'a->Thread.t
Similar to Thread.create, but it picks a background domain at random to run the thread. This ensures that we don't always pick the same domain to run all the various threads needed in an application (timers, event loops, etc.)
run_async runner task schedules the task to run on the given runner. This means task() will be executed at some point in the future, possibly in another thread.
since 0.5
val recommended_thread_count : unit -> int
Number of threads recommended to saturate the CPU. For IO pools this makes little sense (you might want more threads than this because many of them will be blocked most of the time).
A pool within a bigger pool (ie the ocean). Here, we're talking about pools of Thread.t that are dispatched over several Domain.t to enable parallelism.
We provide several implementations of pools with distinct scheduling strategies, alongside some concurrency primitives such as guarding locks (Lock.t) and futures (Fut.t).
Default pool. Please explicitly pick an implementation instead.
val start_thread_on_some_domain : ('a-> unit)->'a->Thread.t
Similar to Thread.create, but it picks a background domain at random to run the thread. This ensures that we don't always pick the same domain to run all the various threads needed in an application (timers, event loops, etc.)
val run_async : ?name:string ->Runner.t->(unit -> unit)-> unit
run_async runner task schedules the task to run on the given runner. This means task() will be executed at some point in the future, possibly in another thread.
parametername
if provided and Trace is present in dependencies, a span will be created when the task starts, and will stop when the task is over. (since NEXT_RELEASE)
since 0.5
val recommended_thread_count : unit -> int
Number of threads recommended to saturate the CPU. For IO pools this makes little sense (you might want more threads than this because many of them will be blocked most of the time).
since 0.5
val spawn : ?name:string ->on:Runner.t->(unit ->'a)->'aFut.t
spawn ~on f runs f() on the runner (a thread pool typically) and returns a future result for it. See Fut.spawn.
parametername
if provided and Trace is present in dependencies, a span will be created for the future. (since NEXT_RELEASE)
since 0.5
val spawn_on_current_runner : ?name:string ->(unit ->'a)->'aFut.t
add key data m returns a map containing the same bindings as m, plus a binding of key to data. If key was already bound in m to a value that is physically equal to data, m is returned unchanged (the result of the function is then physically equal to m). Otherwise, the previous binding of key in m disappears.
before4.03
Physical equality was not ensured.
val update : key->('a option->'a option)->'at->'at
update key f m returns a map containing the same bindings as m, except for the binding of key. Depending on the value of y where y is f (find_opt key m), the binding of key is added, removed or updated. If y is None, the binding is removed if it exists; otherwise, if y is Some z then key is associated to z in the resulting map. If key was already bound in m to a value that is physically equal to z, m is returned unchanged (the result of the function is then physically equal to m).
remove x m returns a map containing the same bindings as m, except for x which is unbound in the returned map. If x was not in m, m is returned unchanged (the result of the function is then physically equal to m).
before4.03
Physical equality was not ensured.
val merge :
+Map (ocaml.Arg_helper.Make.S.Key.Map)
add key data m returns a map containing the same bindings as m, plus a binding of key to data. If key was already bound in m to a value that is physically equal to data, m is returned unchanged (the result of the function is then physically equal to m). Otherwise, the previous binding of key in m disappears.
before4.03
Physical equality was not ensured.
val update : key->('a option->'a option)->'at->'at
update key f m returns a map containing the same bindings as m, except for the binding of key. Depending on the value of y where y is f (find_opt key m), the binding of key is added, removed or updated. If y is None, the binding is removed if it exists; otherwise, if y is Some z then key is associated to z in the resulting map. If key was already bound in m to a value that is physically equal to z, m is returned unchanged (the result of the function is then physically equal to m).
remove x m returns a map containing the same bindings as m, except for x which is unbound in the returned map. If x was not in m, m is returned unchanged (the result of the function is then physically equal to m).