A good place to start is asking yourself, "what happens if my program is not blocking on read(2) on a network socket when a packet comes in"
The answer is not that the router waits until you call read(2) to send it!
A good place to start is asking yourself, "what happens if my program is not blocking on read(2) on a network socket when a packet comes in"
The answer is not that the router waits until you call read(2) to send it!
@miki bzzzzzt, wrong
You want I/O multiplexing to address this case, which is not the same thing as async I/O.
@drewdevault I'd disagree here, a program can be I/O bound (let's say small requests to a slow service / on a slow network), but you might still want to e.g. accept input from the user while the slow service is doing its thing. If you don't have threads or async i/o, you're waiting on the network while the user thinks your program is broken.
One last tip: the purpose of async I/O is to give the CPU back to your program while the I/O operation completes. But if you don't have a plan for what to do with the CPU while you have it, you don't need async I/O.
Async I/O is also often used for I/O multiplexing, which is when you have more than one source of I/O and want to have several I/O operations in flight at the same time, but otherwise you don't need the CPU while they work. You don't need async I/O for that, you need poll(2).
And finally, if your program is I/O bound then you don't need threads.
Also, I can count on one hand the number of programmers I trust to use O_NONBLOCK
@multisn8 lol
for my next pro-tip, don't support windows
@drewdevault ¹except if they turn out useful in edge-cases
like installing lots of files and deferring the closing of those file handles to dedicated threads because Windows Defender™️
e.g. rustup needed that: https://www.youtube.com/watch?v=qbKGw8MQ0i8
Disclaimer: I'm mostly extrapolating from code I've read, articles I've read, a few personal projects that attempt to not needlessly block, and a few experiments with the various APIs.
It might very well be that my understanding of this is incomplete, lacking, or wrong. If anyone here has more experience, feel free to correct me as I'd like to know more about this as well.
On POSIX/Linux, AFAIK the only "real" low-level async I/O API that exists is IO uring (you put work in the ring and it completes at some point in the future). All other APIs are basically variations on the I/O multiplexing model (poll() / epoll() / select()).
There is O_NONBLOCK, but all that does IIUC (correct me if I'm wrong) is to make sure that I/O calls return EAGAIN when too much work is posted at once to do it without blocking, and you need to poll() it again
Even in Async I/O you don't have infinite work to do. At some point you will run out of useful work to do while waiting and you will need to block on I/O (otherwise you will needlessly spin the CPU)
With I/O multiplexing it's the same: you will repeatedly call poll() / epoll() / select() on your file descriptors, and as long as you still have useful work to do while waiting you can pass the timeout as 0 and it will not block if no fd is ready at this point.
1/2
@yrlf @drewdevault @miki isn't the entire async I/O means it wouldn't do the blocking? Whereas I/O multiplexing does blocks the process and continuously check for event on the file descriptor
@drewdevault how exactly does async I/O differ from I/O multiplexing in your understanding?
I/O multiplexing is IIUC having a single thread of execution and using poll() / epoll() / select() / ... to periodically check which I/O is ready and then handling that (either directly or via callbacks). Most nontrivial programs that do that do it via callbacks and an event loop.
1/2
GNU social JP is a social network, courtesy of GNU social JP管理人. It runs on GNU social, version 2.0.2-dev, available under the GNU Affero General Public License.
All GNU social JP content and data are available under the Creative Commons Attribution 3.0 license.