@@ -35,6 +35,8 @@ Eio replaces existing concurrency libraries such as Lwt
3535* [ Running processes] ( #running-processes )
3636* [ Time] ( #time )
3737* [ Multicore Support] ( #multicore-support )
38+ * [ Domain Manager] ( #domain-manager )
39+ * [ Executor Pool] ( #executor-pool )
3840* [ Synchronisation Tools] ( #synchronisation-tools )
3941 * [ Promises] ( #promises )
4042 * [ Example: Concurrent Cache] ( #example-concurrent-cache )
@@ -936,7 +938,12 @@ The mock backend provides a mock clock that advances automatically where there i
936938
937939OCaml allows a program to create multiple * domains* in which to run code, allowing multiple CPUs to be used at once.
938940Fibers are scheduled cooperatively within a single domain, but fibers in different domains run in parallel.
939- This is useful to perform CPU-intensive operations quickly.
941+ This is useful to perform CPU-intensive operations quickly
942+ (though extra care needs to be taken when using multiple cores; see the [ Multicore Guide] ( ./doc/multicore.md ) for details).
943+
944+ ### Domain Manager
945+
946+ [ Eio.Domain_manager] [ ] provides a basic API for spawning domains.
940947For example, let's say we have a CPU intensive task:
941948
942949``` ocaml
@@ -950,7 +957,7 @@ let sum_to n =
950957 !total
951958```
952959
953- We can use [ Eio.Domain_manager ] [ ] to run this in a separate domain:
960+ We can use the domain manager to run this in a separate domain:
954961
955962``` ocaml
956963let main ~domain_mgr =
@@ -977,6 +984,10 @@ let main ~domain_mgr =
977984- : unit = ()
978985```
979986
987+ <p align =' center ' >
988+ <img src =" ./doc/traces/multicore-posix.svg " />
989+ </p >
990+
980991Notes:
981992
982993- ` traceln ` can be used safely from multiple domains.
@@ -988,8 +999,78 @@ Notes:
988999- ` Domain_manager.run ` waits for the domain to finish, but it allows other fibers to run while waiting.
9891000 This is why we use ` Fiber.both ` to create multiple fibers.
9901001
991- For more information, see the [ Multicore Guide] ( ./doc/multicore.md ) .
1002+ ### Executor Pool
1003+
1004+ An [ Eio.Executor_pool] [ ] distributes jobs among a pool of domain workers.
1005+ Domains are reused and can execute multiple jobs concurrently.
1006+
1007+ Each domain worker starts new jobs until the total ` ~weight ` of its running jobs reaches ` 1.0 ` .
1008+ The ` ~weight ` represents the expected proportion of a CPU core that the job will take up.
1009+ Jobs are queued up if they cannot be started immediately due to all domain workers being busy (` >= 1.0 ` ).
1010+
1011+ This is the recommended way of leveraging OCaml 5's multicore capabilities.
1012+
1013+ Usually you will only want one pool for an entire application, so the pool is typically created when the application starts:
1014+
1015+ <!-- $MDX skip -->
1016+ ``` ocaml
1017+ let () =
1018+ Eio_main.run @@ fun env ->
1019+ Switch.run @@ fun sw ->
1020+ let pool =
1021+ Eio.Executor_pool.create
1022+ ~sw (Eio.Stdenv.domain_mgr env)
1023+ ~domain_count:4
1024+ in
1025+ main ~pool
1026+ ```
1027+
1028+ The pool starts its domain workers immediately upon creation.
1029+
1030+ The pool will not block our switch ` sw ` from completing;
1031+ when the switch finishes, all domain workers and running jobs are cancelled.
9921032
1033+ ` ~domain_count ` is the number of domain workers to create.
1034+ The total number of domains should not exceed ` Domain.recommended_domain_count ` or the number of cores on your system.
1035+
1036+ We can run the previous example using an Executor Pool like this:
1037+
1038+ ``` ocaml
1039+ let main ~domain_mgr =
1040+ Switch.run @@ fun sw ->
1041+ let pool =
1042+ Eio.Executor_pool.create ~sw domain_mgr ~domain_count:4
1043+ in
1044+ let test n =
1045+ traceln "sum 1..%d = %d" n
1046+ (Eio.Executor_pool.submit_exn pool ~weight:1.0
1047+ (fun () -> sum_to n))
1048+ in
1049+ Fiber.both
1050+ (fun () -> test 100000)
1051+ (fun () -> test 50000)
1052+ ```
1053+
1054+ <!-- $MDX non-deterministic=output -->
1055+ ``` ocaml
1056+ # Eio_main.run @@ fun env ->
1057+ main ~domain_mgr:(Eio.Stdenv.domain_mgr env);;
1058+ +Starting CPU-intensive task...
1059+ +Starting CPU-intensive task...
1060+ +Finished
1061+ +sum 1..50000 = 1250025000
1062+ +Finished
1063+ +sum 1..100000 = 5000050000
1064+ - : unit = ()
1065+ ```
1066+ ` ~weight ` is the anticipated proportion of a CPU core used by the job.
1067+ In other words, the fraction of time actively spent executing OCaml code, not just waiting for I/O or system calls.
1068+ In the above code snippet we use ` ~weight:1.0 ` because the job is entirely CPU-bound: it never waits for I/O or other syscalls.
1069+ ` ~weight ` must be ` >= 0.0 ` and ` <= 1.0 ` .
1070+ Example: given an IO-bound job that averages 2% of one CPU core, pass ` ~weight:0.02 ` .
1071+
1072+ Each domain worker starts new jobs until the total ` ~weight ` of its running jobs reaches ` 1.0 ` .
1073+
9931074## Synchronisation Tools
9941075
9951076Eio provides several sub-modules for communicating between fibers,
@@ -1241,6 +1322,8 @@ The `Fiber.check ()` checks whether the worker itself has been cancelled, and ex
12411322It's not actually necessary in this case,
12421323because if we continue instead then the following ` Stream.take ` will perform the check anyway.
12431324
1325+ Note: in a real system, you would probably use [ Eio.Executor_pool] [ ] for this rather than making your own pool.
1326+
12441327### Mutexes and Semaphores
12451328
12461329Eio also provides ` Mutex ` and ` Semaphore ` sub-modules.
@@ -1805,6 +1888,7 @@ Some background about the effects system can be found in:
18051888[ Eio.Path ] : https://ocaml-multicore.github.io/eio/eio/Eio/Path/index.html
18061889[ Eio.Time ] : https://ocaml-multicore.github.io/eio/eio/Eio/Time/index.html
18071890[ Eio.Domain_manager ] : https://ocaml-multicore.github.io/eio/eio/Eio/Domain_manager/index.html
1891+ [ Eio.Executor_pool ] : https://ocaml-multicore.github.io/eio/eio/Eio/Executor_pool/index.html
18081892[ Eio.Promise ] : https://ocaml-multicore.github.io/eio/eio/Eio/Promise/index.html
18091893[ Eio.Stream ] : https://ocaml-multicore.github.io/eio/eio/Eio/Stream/index.html
18101894[ Eio_posix ] : https://ocaml-multicore.github.io/eio/eio_posix/Eio_posix/index.html
0 commit comments