Concurrency: Lwt and Eio

Key functions: Lwt.return, Lwt.bind / >>=, Lwt.map / >|=, Lwt.join, Lwt.all, Lwt.pick, Lwt.choose, Lwt.catch, Lwt_list.map_p, Lwt_stream, Lwt_mvar.

37.1 Lwt — monadic cooperative concurrency (mature, widely used)

Key functions: Lwt.return, Lwt.bind / >>=, Lwt.map / >|=, Lwt.join, Lwt.all, Lwt.pick, Lwt.choose, Lwt.catch, Lwt_list.map_p, Lwt_stream, Lwt_mvar.

open Lwt.Syntax

let fetch_both () =
  let* () = Lwt_io.printl "starting" in
  let a = Lwt_unix.sleep 1.0 |> Lwt.map (fun () -> "a") in
  let b = Lwt_unix.sleep 1.0 |> Lwt.map (fun () -> "b") in
  let* ra = a and* rb = b in                (* concurrent: ~1s total *)
  Lwt_io.printlf "%s %s" ra rb

let () = Lwt_main.run (fetch_both ())

37.2 Eio — direct-style, effects-based I/O (OCaml 5)

Structured concurrency with Eio.Switch — fibers cannot outlive their switch.

Capabilities: access to network/fs/clock passed explicitly via env.

Eio.Fiber.fork, Fiber.all, Fiber.any, Eio.Promise, Eio.Stream, Eio.Mutex.

Parallelism: Eio.Domain_manager.run, Eio.Executor_pool.

Backends: io_uring on Linux, posix, Windows.

let main env =
  let clock = Eio.Stdenv.clock env in
  Eio.Fiber.both
    (fun () -> Eio.Time.sleep clock 1.0; Eio.traceln "fiber A")
    (fun () -> Eio.Time.sleep clock 1.0; Eio.traceln "fiber B")

let () = Eio_main.run main
(* Eio TCP echo server *)
let handle flow _addr = Eio.Flow.copy flow flow

let () = Eio_main.run @@ fun env ->
  Eio.Switch.run @@ fun sw ->
  let net = Eio.Stdenv.net env in
  let sock = Eio.Net.listen net ~sw ~backlog:5 ~reuse_addr:true (`Tcp (Eio.Net.Ipaddr.V4.loopback, 8080)) in
  Eio.Net.run_server sock handle ~on_error:(fun e -> Eio.traceln "error: %a" Fmt.exn e)

37.3 Async (Jane Street)

Deferred.t monad, similar to Lwt; used with Core.

37.4 Choosing

huge ecosystem, OCaml 4 & 5, js_of_ocaml Jane Street stack direct-style (effects) new OCaml 5 projects, structured concurrency lightweight alternative scheduler