(no title)
talex5 | 4 years ago
- domainslib schedules all tasks across all cores (like Go).
- eio keeps tasks on the same core (and you can use a shared job queue to distribute work between cores if you want).
Eio can certainly do async IO on multiple cores.
Moving tasks freely between cores has some major downsides - for example every time a Go program wants to access a shared value, it needs to take a mutex (and be careful to avoid deadlocks). Such races can be very hard to debug.
I suspect that the extra reliability is often worth the cost of sometimes having unbalanced workloads between cores. We're still investigating how big this effect is. When I worked at Docker, we spent a lot of time dealing with races in the Go code, even though almost nothing in Docker is CPU intensive!
For a group of tasks on a single core, you can be sure that e.g. incrementing a counter or scanning an array is an atomic operation. Only blocking operations (such as reading from a file or socket) can allow something else to run. And eio schedules tasks deterministically, so if you test with (deterministic) mocks then the trace of your tests is deterministic too. Eio's own unit-tests are mostly expect-based tests where the test just checks that the trace output matches the recorded trace, for example.
The Eio README has more information, plus a getting-started guide: https://github.com/ocaml-multicore/eio/blob/main/README.md
Zababa|4 years ago
Now let's imagine I want to do the same program in OCaml. I think my options are:
- on current OCaml, thread-based concurrency but no parallelism
- on current OCaml, monadic concurrency (Lwt, Async) but no parallelism
- on multicore OCaml, direct/effect-based (I'm not sure what's the right word) concurrency with eio, which is deterministic. If I want parallelism here, I have to explicitely create and use a shared job queue, while the Go runtime does this implicitly. Since the standard library Queue is not thread safe, I would have to use Mutex to avoid concurrent access.
Is this correct? I've read the eio documentation but it's hard to wrap my head around all of that without examples. I've found the Domain_manager which looks like what I want. For example, I could have the main thread fill the queue and for each core available, I could launch a Domain_manager.run toto, with toto taking jobs from the queue that would be shared between all domains?
talex5|4 years ago
The README shows an example of a pool of workers pulling jobs from an Eio.Stream:
https://github.com/ocaml-multicore/eio#example-a-worker-pool
We're still exploring what APIs to provide for this kind of thing, and in particular how to unify domainslib and eio.
mst|4 years ago
See the example near the end of https://raku-advent.blog/2021/12/01/batteries-included-gener... for what I mean.