Multicore Parallelism
Spawn few domains (≈ number of cores); they're expensive.
36.1 Domains — units of parallelism (OS threads, one per core)
Spawn few domains (≈ number of cores); they're expensive. Use a pool for fine-grained tasks.
let fib_par n =
let rec fib n = if n < 2 then n else fib (n - 1) + fib (n - 2) in
let d1 = Domain.spawn (fun () -> fib (n - 1)) in
let d2 = Domain.spawn (fun () -> fib (n - 2)) in
Domain.join d1 + Domain.join d2
let cores = Domain.recommended_domain_count ()36.2 Atomics
let counter = Atomic.make 0
let () =
let ds = List.init 4 (fun _ -> Domain.spawn (fun () ->
for _ = 1 to 100_000 do Atomic.incr counter done)) in
List.iter Domain.join ds;
Printf.printf "%d\n" (Atomic.get counter) (* 400000 *)
Atomic.get, Atomic.set, Atomic.exchange, Atomic.compare_and_set, Atomic.fetch_and_add36.3 Mutex, Condition, Semaphore
let m = Mutex.create ()
let shared = ref []
let add x = Mutex.protect m (fun () -> shared := x :: !shared) (* 5.1+ *)
let c = Condition.create ()
(* Condition.wait c m; Condition.signal c; Condition.broadcast c *)
Semaphore.Counting.make 3, Semaphore.Binary.make true36.4 Domain-local storage
let key = Domain.DLS.new_key (fun () -> Random.State.make_self_init ())
let rand () = Random.State.int (Domain.DLS.get key) 10036.5 Domainslib — task pools, parallel for
module T = Domainslib.Task
let parallel_sum arr =
let pool = T.setup_pool ~num_domains:(Domain.recommended_domain_count () - 1) () in
let result = T.run pool (fun () ->
T.parallel_for_reduce pool ( + ) 0 ~start:0 ~finish:(Array.length arr - 1)
~body:(fun i -> arr.(i))) in
T.teardown_pool pool;
result
let rec pfib pool n =
if n < 20 then (let rec f n = if n < 2 then n else f (n-1) + f (n-2) in f n)
else
let a = T.async pool (fun () -> pfib pool (n - 1)) in
let b = pfib pool (n - 2) in
T.await pool a + b36.6 Memory model & data races
OCaml 5 has a bounded data-race memory model: racy programs don't crash or exhibit undefined behaviour like C; races are local in effect. Still, protect shared mutable state with Atomic/Mutex, or use lock-free structures from Saturn (saturn library: queues, stacks, hashtables).
36.7 Threads (systhreads)
The threads library still exists for concurrency within a domain (with a per-domain lock): Thread.create, Thread.join. Use for blocking I/O compatibility, not CPU parallelism.
36.8 Tools
ThreadSanitizer (TSan) support: opam switch create 5.x+tsan detects data races.
Olly / runtime_events: observe GC and domain events.