How to create a large number of threads in OCaml?

I found a topic in the Racket group on channelcreation performance .

I want to write an OCaml version for testing.

let post (c,x) = Event.sync (Event.send c x);;

let accept c = Event.sync (Event.receive c);;

let get_chan c = let n = accept c in print_int n;print_newline ();;

let chan_trans (old_chan, new_chan) =
  let s = accept old_chan in
  post (new_chan,(s+1));;

let rec whisper count init_val =
  let rec aux n chan =
    if n >= count then chan
    else
      let new_chan = Event.new_channel ()
      in Thread.create chan_trans (chan, new_chan);
      aux (n+1) new_chan
  in let leftest_chan = Event.new_channel ()
  in let t0 = Thread.create post (leftest_chan, init_val)
  in let rightest_chan = aux 0 leftest_chan
  in get_chan rightest_chan;;

whisper 10000 1;;
Question: when I tested whisper 1000 1, it produced 1001, as expected. However, when I tried to test whisper 10000 1, there was an error like

Fatal error: Sys_error exception ("Thread.create: resource is temporarily unavailable")

I used this command to compile and run

ocamlc -thread unix.cma threads.cma -o prog whisper.ml &. / prog -I + threads

+4
source share
2 answers

OCaml Thread uses threads of a real system (kernel). The total number of threads is limited by the kernel:

 cat /proc/sys/kernel/threads-max
 251422

, ,

 echo 100000 > /proc/sys/kernel/threads-max

.

let rec whisper count init_val =
  let rec aux n t chan =
    if n >= count then chan
    else
      let new_chan = Event.new_channel () in
      let t' = Thread.create chan_trans (chan, new_chan) in
      Thread.join t;
      aux (n+1) t' new_chan in
  let leftest_chan = Event.new_channel () in
  let t = Thread.create post (leftest_chan, init_val) in
  let rightest_chan = aux 0 t leftest_chan in
  get_chan rightest_chan

. :

$ ocamlbuild -use-ocamlfind -tag thread -pkg threads ev.native
$ time ./ev.native 
100001

real    0m1.581s

. ( ). Lwt Async. .

Lwt

Go , , OCaml ( , ).

open Lwt.Infix

let whispers n =
  let rec whisper i p =
    if i < n then
      Lwt_mvar.take p >>= fun x ->
      whisper (i+1) (Lwt_mvar.create (x+1))
    else Lwt_mvar.take p in
  whisper 0 (Lwt_mvar.create 1)

let () = print_int @@ Lwt_main.run (whispers 100000)

:

$ ocamlbuild -use-ocamlfind -tag thread -pkg lwt.unix lev.native --
$ time ./lev.native 
100001
real    0m0.007s

Go :

$ go build whispers.go 
$ time ./whispers 
100001

real    0m0.952s

""

Go. , , , OCaml Lwt , 100_000 100_001, , whisper , , . , . 50 .

, . Go. 100_001 100_000 , . , . , Go .

let whispers n =
  let rec loop i p =
    if i < n then
      let p' = Lwt_mvar.create_empty () in
      let _t =
        Lwt_mvar.take p >>= fun x ->
        Lwt_mvar.put p' (x+1) in
      loop (i+1) p'
    else Lwt_mvar.take p in
  let p0 = Lwt_mvar.create_empty () in
  let t = loop 1 p0 in
  Lwt_mvar.put p0 1 >>= fun () -> t

$ time ./lev.native
100001
real    0m0.111s

, , 20 ( 1 ), - 10 , Go.

+9

, , , , lwt, " OCaml". :

let whisper left right =
  let%lwt n = Lwt_mvar.take right in
  Lwt_mvar.put left (n+1)

let main () =
  let n = 100_000 in
  let%lwt () = Lwt_io.printf "With %d mvars!\n" n in
  let leftmost = Lwt_mvar.create_empty () in
  let rec setup_whispers left i =
    if  i >= n
    then left
    else let right = Lwt_mvar.create_empty () in
      let () = Lwt.async (fun () -> whisper left right) in
      setup_whispers right (i+1) in
  let rightmost = setup_whispers leftmost 0 in
  let%lwt () = Lwt_mvar.put rightmost 1 in
  let%lwt res = Lwt_mvar.take leftmost in
  Lwt_io.printf "%d\n" res

let () = Lwt_main.run (main ())

$ ocamlbuild -use-ocamlfind -pkg lwt,lwt.ppx,lwt.unix whisper.native
$ time ./whisper.native
With 100000 mvars!
100001

real    0m0.169s
user    0m0.156s
sys 0m0.008s
+3

Source: https://habr.com/ru/post/1620350/


All Articles