Skip to content

janestreet/parallel

Repository files navigation

Parallelism

lib/parallel provides a fork-join interface for parallelism in multi-core OxCaml.

To expose an opportunity for parallelism, user code calls a fork_join function, such as:

(** [fork_join2 t f g] runs [f] and [g] as parallel tasks and returns their results. If
    either task raises, this operation will reraise the leftmost exception after both
    tasks have completed or raised.

    [f] and [g] are [shareable], so can capture both [shared] and [uncontended]
    references. This allows the tasks to read (but not mutate) state from the environment.
    [f] is also [forkable], so cannot capture capsule passwords. *)
val fork_join2
  :  t @ local
  -> (t @ local -> 'a) @ forkable local once shareable
  -> (t @ local -> 'b) @ once shareable
  -> #('a * 'b)

The two functions passed to fork_join2 will (potentially) be executed in parallel. After both functions return, fork_join2 returns a tuple containing both results. Fork-joins may be arbitrarily nested and do not require creating a thread or fiber for each task.

The type Parallel.t represents an implementation of parallelism. To receive a Parallel.t, a parallel computation must be submitted to a separate scheduler library. Schedulers provide the following function:

(** [with_parallel ?max_workers f] creates a scheduler that uses up to [max_workers]
    worker threads, spawns [f] into it, and blocks the current thread until [f] is done
    executing. Returns the result of [f]. *)
val with_parallel
  :  ?max_workers:int (* Default: [Multicore.max_domains ()] *)
  -> (Parallel_kernel.t @ local -> 'a) @ once
  -> 'a

Calling with_parallel provides your parallel computation with a local Parallel.t that represents the ability to run parallel tasks on this scheduler.

The currently available schedulers are:

  • Parallel.Sequential, which runs all tasks on the domain that created it.

  • Parallel_scheduler, which creates a pool of worker domains that pull tasks from per-domain work-stealing dequeues.

Concurrency

The work-stealing scheduler integrates with lib/concurrent to provide non-blocking operations. More documentation coming soon.

Data Race Freedom

lib/parallel makes use of modes to prohibit data races at compile time. The primary restriction on user programs is that they must provide portable functions to fork_join. In brief, portable functions do not close over unprotected mutable state. Refer to the data-race-freedom documentation for further detail.

Full Example

let rec fib parallel n =
  match n with
  | 0 | 1 -> 1
  | n ->
    let #(a, b) =
      Parallel.fork_join2
        parallel
        (fun parallel -> fib parallel (n - 1))
        (fun parallel -> fib parallel (n - 2))
    in
    a + b
;;

let fib_sequential n = printf "%d" (fib Parallel.sequential n)

let fib_parallel n =
  Parallel_scheduler.with_parallel (fun parallel -> printf "%d" (fib parallel n))
;;

About

OxCaml Parallelism

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages