5 ms·
Imho in this area there is really no general good solution: Either you use the leaky blocking IO abstraction over the async IO - and you will require multiple t
by Matthias247 11y ago
Imho in this area there is really no general good solution: Either you use the leaky blocking IO abstraction over the async IO - and you will require multiple threads/tasks for doing anything more complicated and lots of complex synchronization. Or you use the async APIs directly and need to work with callbacks/promises/etc., but you can at least avoid synchronization.
I personally prefer the async solution, and I think async/await is a good solution to make async code a little more readable.
- rdtsc 11y ago> Either you use the leaky blocking IO abstraction over the async IO What do you mean the leaky blocking IO. It is the non-blocking IO that is leaky, isn't it. If at the business logic there is a request being processed that needs to go through steps a,b,c and then return. b, can't be done unless a finishes and c unless b finishes is mapped pretty cleanly to an execution context of a thread/actor/goroutine/task/process. Shoving IO callback functions in between handling the steps, or spreading them across callbacks or using promises is leaking the abstraction of the platform not being able to handle concurrent processing very well.
- Matthias247 11y agoWhat I meant is that blocking IO is a leaking abstraction, because IO is always asynchronous. What blocking does is adding an extra step (start the process AND waiting for the result) and thereby hiding something. I agree that if you have some pure linear steps (do A, then do B, then do C, and probably use the result from the last step for the next), then the synchronous abstractions work fine. But as soon as you add various timeouts, different error handling strategies, multicast communication, cancellation and other stuff to your async IO procesing then it isn't purely linear anyway. I often end up implementing quite complex state machines for heavy IO related code, and for this I am more happy with working in an asynchronous single-threaded environment.
- deleted 11y ago[deleted]
- rdtsc 11y ago> because IO is always asynchronous. Creating a socket() creates a blocking socket by default, doesn't it. Doing a recv on it, blocks the current thread. Pretty sure by default IO is synchronous. Sure at some point they are all connected to a single wire plugged into the switch and there is a single network card. But if you are thinking that low, then well javascript is not the framework to talk about we are in firmware, dpdk, and driver land. The socket API is synchronous. Do do stuff "asynchronously" you have to go the extra mile and enable turn on some options, use select/poll/epoll callbacks, explicitly pass state around between callbacks etc. > What blocking does is adding an extra step (start the process AND waiting for the result) and thereby hiding something. See to me at the socket layer non-blocking is the extra step. Having to enable a new mode, then use some extra polling hub to see which socket has data etc. That mixes context between separate requests, etc. > I often end up implementing quite complex state machines for heavy IO related code In specializes cases for performance reasons I think switching to asynchronous, but that is a rather special case. It works for short callback chains and situations optimized for IO throughput say things like nginx or haproxy. Doing it for an online store or some business middle layer would be very tricky.
- Matthias247 11y agoThat the default posix socket API is in blocking mode by default was a decision that was made lots of years ago and for some specific reasons. If the reasons at that time might have been different, then it could now also be async by default. So I don't think that tells us whether one or the other model is the more natural or a better one. Look at the LWIP library for embedded for example. There the async API is the default one, and you have to take the extra mile (and some performance hit) to get the blocking behavior. The midori OS prototype also seems to have implemented a pure async IO subsystem. I also think it depends on the use-case whether one or the other model is more appealing, but I don't think it's only for performance reasons. A lot of people here think about IO mainly in terms of http request processing because web services are the usual domain here. For this such applications I think blocking abstractions come quite naturally, because you there you read the input stream once, then do a sequence of intermediate processing steps and then write a response. If you instead are working on other domains (writing a message broker, a gateway application, http/2 library, realtime sensordata processing system, ...) where there is no linear sequence of read/write operations and where you have shared state between your IO endpoints then your needs and the preferred building blocks might be different.