Select in OCaml

Our example demonstrates how to use the select construct in OCaml to wait on multiple channel operations. Combining threads and channels with select is a powerful feature.

open Unix

let main () =
  (* For our example we'll select across two channels. *)
  let c1 = Event.new_channel () in
  let c2 = Event.new_channel () in

  (* Each channel will receive a value after some amount
     of time, to simulate e.g. blocking RPC operations
     executing in concurrent threads. *)
  let _ = Thread.create (fun () ->
    Thread.delay 1.0;
    Event.sync (Event.send c1 "one")
  ) () in
  let _ = Thread.create (fun () ->
    Thread.delay 2.0;
    Event.sync (Event.send c2 "two")
  ) () in

  (* We'll use `select` to await both of these values
     simultaneously, printing each one as it arrives. *)
  for _ = 1 to 2 do
    match Event.select [Event.receive c1; Event.receive c2] with
    | s when s == Event.receive c1 ->
        let msg = Event.sync s in
        Printf.printf "received %s\n" msg
    | s ->
        let msg = Event.sync s in
        Printf.printf "received %s\n" msg
  done

let () = main ()

To run this program:

$ ocamlc -thread unix.cma threads.cma select.ml -o select
$ ./select
received one
received two

Note that the total execution time is only ~2 seconds since both the 1 and 2 second delays execute concurrently.

In this OCaml version:

  1. We use the Event module from the standard library to create channels and handle communication.
  2. Threads are created using Thread.create instead of goroutines.
  3. The select statement is replaced with Event.select, which works similarly but returns an event that we then need to synchronize on.
  4. Pattern matching is used to determine which channel received a message.

This example demonstrates how OCaml can handle concurrent operations and channel-based communication, similar to the original example.