On Mon, Sep 8, 2014 at 12:05 PM, Stephen Dolan <stephen.dolan@cl.cam.ac.uk> wrote:
Generally, we're going to try to avoid blocking C calls and instead
use select/poll/kqueue/epoll to handle blocking I/O. From the fiber's
point of view, this looks like normal blocking I/O, except if a system
call returns EWOULDBLOCK we'll switch to another fiber until the I/O
is ready.

This doesn't work for a (portable) implementation of File I/O which is why everyone else (Go, Erlang, Haskell, ...) either has a pool of threads for handling these (Erlang), or they just create another thread for handling it, up to a point (Go). Network I/O is simple however, since you can batch those on a standard epoll/kqueue/poll/select loop.

The problem is that for file descriptors representing (kernel) file objects, they never return EWOULDBLOCK since you can always write to them (rather subtle semantics). But once you write to them, that thread is off to kernelspace and you only get it back milliseconds later when the write is complete. In the meantime that thread is placed in uninterruptible sleep. The async File I/O implementations are not portable either, which is why everyone ends up with having process pools for this or ends up spawning threads. Go's rationale is that file I/O is probably going to take so long anyway that it doesn't really cost too much to create another thread (given that you also run a thread cache of where to hand off the domain). This URI has a high-level overview of the Go style:

http://morsmachine.dk/go-scheduler

and there are nice isomorphisms to the concept of fiber (G) and domain (P) and thread (M).


--
J.