@@ -35,6 +35,8 @@ Eio replaces existing concurrency libraries such as Lwt
35
35
* [ Running processes] ( #running-processes )
36
36
* [ Time] ( #time )
37
37
* [ Multicore Support] ( #multicore-support )
38
+ * [ Domain Manager] ( #domain-manager )
39
+ * [ Executor Pool] ( #executor-pool )
38
40
* [ Synchronisation Tools] ( #synchronisation-tools )
39
41
* [ Promises] ( #promises )
40
42
* [ Example: Concurrent Cache] ( #example-concurrent-cache )
@@ -936,7 +938,12 @@ The mock backend provides a mock clock that advances automatically where there i
936
938
937
939
OCaml allows a program to create multiple * domains* in which to run code, allowing multiple CPUs to be used at once.
938
940
Fibers 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.
940
947
For example, let's say we have a CPU intensive task:
941
948
942
949
``` ocaml
@@ -950,7 +957,7 @@ let sum_to n =
950
957
!total
951
958
```
952
959
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:
954
961
955
962
``` ocaml
956
963
let main ~domain_mgr =
@@ -992,8 +999,78 @@ Notes:
992
999
- ` Domain_manager.run ` waits for the domain to finish, but it allows other fibers to run while waiting.
993
1000
This is why we use ` Fiber.both ` to create multiple fibers.
994
1001
995
- 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.
1032
+
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 ` .
996
1071
1072
+ Each domain worker starts new jobs until the total ` ~weight ` of its running jobs reaches ` 1.0 ` .
1073
+
997
1074
## Synchronisation Tools
998
1075
999
1076
Eio provides several sub-modules for communicating between fibers,
@@ -1245,6 +1322,8 @@ The `Fiber.check ()` checks whether the worker itself has been cancelled, and ex
1245
1322
It's not actually necessary in this case,
1246
1323
because if we continue instead then the following ` Stream.take ` will perform the check anyway.
1247
1324
1325
+ Note: in a real system, you would probably use [ Eio.Executor_pool] [ ] for this rather than making your own pool.
1326
+
1248
1327
### Mutexes and Semaphores
1249
1328
1250
1329
Eio also provides ` Mutex ` and ` Semaphore ` sub-modules.
@@ -1809,6 +1888,7 @@ Some background about the effects system can be found in:
1809
1888
[ Eio.Path ] : https://ocaml-multicore.github.io/eio/eio/Eio/Path/index.html
1810
1889
[ Eio.Time ] : https://ocaml-multicore.github.io/eio/eio/Eio/Time/index.html
1811
1890
[ 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
1812
1892
[ Eio.Promise ] : https://ocaml-multicore.github.io/eio/eio/Eio/Promise/index.html
1813
1893
[ Eio.Stream ] : https://ocaml-multicore.github.io/eio/eio/Eio/Stream/index.html
1814
1894
[ Eio_posix ] : https://ocaml-multicore.github.io/eio/eio_posix/Eio_posix/index.html
0 commit comments