Proposal: Custom event loops #9922
Labels
proposal
This issue suggests modifications. If it also has the "accepted" label then it is planned.
standard library
This issue involves writing Zig code for the standard library.
Milestone
One thing that made sense and that was made clear in #8224 was that one event loop implementation cannot fit all uses. Even a configurable event loop would just end up being very complex and still lack some niche requirement for an event loop. For example, an I/O heavy application might want to use an event loop that could be backed by APIs like io_uring, whereas a CPU-bound application might want to have finer grained control of resources, have less yield overhead, use a priority queue, etc.
Currently, it is possible to make a custom event loop, however it doesn't work with the standard library I/O abstractions, which means I/O have to be reimplemented using
std.os
in order to be integrated with the custom event loop. This is less than optimal, produces error-prone code and is duplicating code from the standard library to a program.What I propose here is an API to use custom event loop implementations which could work the same way that currently a function can take a reader or a writer (using
anytype
) or the way a function takes an allocator (using "interfaces").If a program wants to be synchronous, it would simply have to pass around a loop implementation that executes everything synchronously instead of using an opaque
io_mode
variable.One important question if we want to implement it is whether to pass the event loop as an argument (like we currently do with allocators) or pass it in a global variable (which is currently done with
io_mode
)If we pass it as an argument it could make some APIs feel "heavier" to use, but hopefully the way reader and writer are abstracted (and common sense that it isn't generally good idea to mix two different event loops for reading and writing) means that the context (for example,
File
) would handle the event loop. Opening a file could look like this:As you can see, one major flaw is that now whether it is asynchronous or not is now heavily visible, this can be viewed as a flaw because it makes async functions "colored", or it could be seen as following the "No hidden control flow." zen. Comments on that would be much appreciated.
Another way is to keep the global variable, in which the case the above code doesn't change from what we currently do today:
Like it is in the current status quo, looking at this code,
reader.readBytesNoEof
could either start an async function, wait for I/O using epoll or some other API, and return, or it could use the synchronousread
system call.However this might not be actually a bad thing or a case of hidden control flow, as the outcome from the function is usually the same.
Anyway, this is more of a request for comments than a direct proposal. So I'm open for any critique, point to make, or other.
The text was updated successfully, but these errors were encountered: