Live data from Hacker News

Asynchronous IO: the next billion-dollar mistake?

yorickpeterse.com

101–110 of 165 posts

Re: Asynchronous IO: the next billion-dollar mistake?

#101
post #51
post #40

Earlier quoted context omitted.

> It's a simple, clean model - no need for locks. Nit: You can very easily have race conditions in async JS. There are all sorts of Mutex-style structures for async.

That's really interesting. Care to share a link to 1 or 2 real world examples of this that you've seen? Or even better, examples of how one would write such locks in JS that would be effective against these type of race conditions?

Conceptually, what happened was

  foo.a = a;
  foo.b = await b(); // while waiting for b's completion, something happens that changes the value of `a`, making `foo` invalid
(or more complex variants of this)

In a multi-threaded model, this would be classified as a race condition on `a`. That's why Rust has RefCell for r/w data sharing in single-threaded code.

I don't remember the exact details, but I was hit by this many times when refactoring e.g. db access or file access in the (JS) code of Firefox. This can happen without async/await, without Promise and even without an event loop, you just need callbacks. But of course, having an event loop, Promise and async/await give you way more opportunities to hit such an issue.

Re: Asynchronous IO: the next billion-dollar mistake?

#103

Somewhat controversial take: the current threads implementation is usually already performant enough for most use cases. The actual reason why we don't use them to handle more than a few thousand concurrent operations is that, at least in Linux, threads are scheduled and treated very similarly to processes. E.g. if a single process with 3000 threads gets bottlenecked on some syscall, etc, your system load average wil…

> your system load average will become 3000, and it will essentially lead to no other processes being able to run well on the same machine.

That doesn't sound right. I mean, there are many schedulers available, but I was under the impression that most have a separate blocked queue. (Or more specifically, anything blocked will not be in the runnable pool - those will be dequeued) I.e. anything waiting on a syscall will be mostly ignited.

(Please correct me if I'm misunderstanding the usual behaviour here)

Re: Asynchronous IO: the next billion-dollar mistake?

#104

Async IO is not only about creating sockets and spawning threads. Idea of async IO is that the world is not controlled by your CPU. There are network, storage, sound devices that might and will take time to produce the result and the CPU has to wait for it. I feel like there is a big misunderstanding about what async IO is and what problem it solves.

Doesn't message passing capture this essence better?

Re: Asynchronous IO: the next billion-dollar mistake?

#105
post #82
post #54

Earlier quoted context omitted.

No, the hardware is frequently inherently asynchronous. You write some memory and then the hardware consumes the prepared data asynchronously, in parallel, until it informs you in some manner that the operation is complete (usually either a asynchronous interrupt, or asynchronous write to a location you are polling). You can do whatever you want after preparing the data without waiting for completion. That is a inher…

While that is technically true, it's also missing the point entirely. That's why I said you can have either blocking sync or non-blocking async. The article explicitly talks about the API provided by the OS. As a matter of fact, they're even more specific talking about spawning os threads vs async non-blocking file access. At this level, the async is an implementation detail. I guess your comment confirms that you di…

No, it shows you did not understand the context or the point of the comment you originally responded to.

The author wants both synchronous and asynchronous modes, but they complain it is painful to provide asynchronous modes using synchronous primitives due to limitations of OS handling for such cases.

dist1ll was pointing out how the lower abstraction level, the hardware, actually presents a asynchronous interface. As such, the higher abstraction level the author of the article was complaining about, the OS API (which is a software implementation detail) lacks hardware sympathy.

The implication being that instead of the hardware presenting a asynchronous API, that the OS transduces into a synchronous API, that the author must transduce back into a asynchronous API; it might be simpler if the OS just directly presents the underlying asynchronous API and the author can transduce that into a synchronous API where needed. That involves fewer layers, fewer conversions, more hardware sympathy, and sidesteps the OS limitations preventing simple implementation of asynchronous modes using synchronous primitives.

Basically, if you have one wrong, you should not make a second wrong to make a right. You should just drop the first wrong. That is not obvious if you do not realize you are starting from or assuming one wrong.

Re: Asynchronous IO: the next billion-dollar mistake?

#106
post #63

Async IO is hilarious in a universe where Hewitt's actors or even Hoare's CSP exist. They are a subpar technique that works well with languages with semantics from the 1970s that do not have communication primitives, in the age of multicore and the Internet. The saddest thing is the most hyped language of the decade went all in with this miserable idea, and turned me completely off the ecosystem.

What problems do you have with async io? I try to imagine and can’t see how it is bad. It’s completely transparent and non-problematic to me.

Also, what’s the most hyped lang of the decade? Go, Kotlin?

Re: Asynchronous IO: the next billion-dollar mistake?

#107
post #10

Asynchronous IO isn't about efficiency. The approach the author takes with their language is just threads, but scheduled in userland. This model allows a decoupling of the performance characteristics of runtime threads from OS threads - which can sometimes be beneficial - but essentially, the programming model is fundamentally still synchronous. Asynchronous programming with async/await is about revealing the time di…

> Take cancellation for example: cancelling tasks under the synchronous programming model requires passing a context object through every part of your code that might call down into an IO operation. Does it? Wouldn’t you just kill the thread in the synchronous model?

Cancellation is just a boolean that is checked between smaller increments of the full job

Re: Asynchronous IO: the next billion-dollar mistake?

#108
post #22

Earlier quoted context omitted.

One of the other aspects of this is that implementing a synchronous model on top of asynchronous primitives is absolutely trivial. You just wait until the asynchronous operation completes. Any program designed for asynchronous execution can be trivially retrofitted for synchronous execution. In contrast, implementing a asynchronous model on top of synchronous primitives is extremely challenging requiring the current…

It's also very easy to implement a future/promise style API over a blocking IO primitive, as long as you have cheap threads: you spawn a thread that executes the blocking operation (with cancelation and timeout support as needed) and sets the future's result once the result is done, or some error state. It's really not such a huge problem. I will also note that most async runtimes include much more complex program re…

Yes, if you have cheap threads at the required scale. But that is the entire problem as you also attest and agree that with the author and me that OS threads do not scale to the required level.

Asynchronous, non-blocking primitives do scale to the required level, demonstrate greater hardware sympathy, and can easily and practically be used for the other half of the equation, blocking I/O, at the required scale.

Asynchronous primitives robustly solve the entire problem space, where as synchronous primitives suffer in high concurrency cases.

The only reason to prefer only exposing/implementing synchronous primitives in the API is due to implementation complexity. But at the OS layer you are abstracting hardware interfaces that almost always present asynchronous interfaces. Thus, exposing asynchronous APIs is usually not very hard where as exposing synchronous APIs is actually a mismatch that requires smoothing over (though to be fair not very much since, as I mentioned previously, implementing a synchronous operation in terms of asynchronous primitives is quite easy).

Though in truth I think we largely agree anyways. I was just presenting a more complete explanation.

Re: Asynchronous IO: the next billion-dollar mistake?

#109

Somewhat controversial take: the current threads implementation is usually already performant enough for most use cases. The actual reason why we don't use them to handle more than a few thousand concurrent operations is that, at least in Linux, threads are scheduled and treated very similarly to processes. E.g. if a single process with 3000 threads gets bottlenecked on some syscall, etc, your system load average wil…

> your system load average will become 3000, and it will essentially lead to no other processes being able to run well on the same machine. That doesn't sound right. I mean, there are many schedulers available, but I was under the impression that most have a separate blocked queue. (Or more specifically, anything blocked will not be in the runnable pool - those will be dequeued) I.e. anything waiting on a syscall wil…

Yeah I think you are right, it depends on the syscalls, etc, in question. When that happened I didn't check which exact syscalls were being used

Re: Asynchronous IO: the next billion-dollar mistake?

#110
post #71
post #54

Earlier quoted context omitted.

No, the hardware is frequently inherently asynchronous. You write some memory and then the hardware consumes the prepared data asynchronously, in parallel, until it informs you in some manner that the operation is complete (usually either a asynchronous interrupt, or asynchronous write to a location you are polling). You can do whatever you want after preparing the data without waiting for completion. That is a inher…

Hardware is even-driven not asynchronous (the event-driven paradigm is an asynchronous paradigm, but I assume here you mean asynchronous as in async/await)

[deleted]
Post reply on HN