diff --git a/README.md b/README.md index b06a1975..5135d00b 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,17 @@ The user can create several thread pools (implementing the interface `Runner.t`) These pools use regular posix threads, but the threads are spread across multiple domains (on OCaml 5), which enables parallelism. +Current we provide these pool implementations: +- `Fifo_pool` is a thread pool that uses a blocking queue to schedule tasks, + which means they're picked in the same order they've been scheduled ("fifo"). + This pool is simple and will behave fine for coarse-granularity concurrency, + but will slow down under heavy contention. +- `Ws_pool` is a work-stealing pool, where each thread has its own local queue + in addition to a global queue of tasks. This is efficient for workloads + with many short tasks that spawn other tasks, but the order in which + tasks are run is less predictable. This is useful when throughput is + the important thing to optimize. + The function `Runner.run_async pool task` schedules `task()` to run on one of the workers of `pool`, as soon as one is available. No result is returned by `run_async`. @@ -159,6 +170,10 @@ On OCaml 5, again using effect handlers, the module `Fork_join` implements the [fork-join model](https://en.wikipedia.org/wiki/Fork%E2%80%93join_model). It must run on a pool (using [Runner.run_async] or inside a future via [Fut.spawn]). +It is generally better to use the work-stealing pool for workloads that rely on +fork-join for better performance, because fork-join will tend to spawn lots of +shorter tasks. + ```ocaml # let rec select_sort arr i len = if len >= 2 then ( diff --git a/src/ws_deque_.mli b/src/ws_deque_.mli index bead45aa..b696224e 100644 --- a/src/ws_deque_.mli +++ b/src/ws_deque_.mli @@ -1,6 +1,10 @@ (** Work-stealing deque. - Adapted from "Dynamic circular work stealing deque", Chase & Lev + Adapted from "Dynamic circular work stealing deque", Chase & Lev. + + However note that this one is not dynamic in the sense that there + is no resizing. Instead we return [false] when [push] fails, which + keeps the implementation fairly lightweight. *) type 'a t