Live data from Hacker News

Asynchronous IO: the next billion-dollar mistake?

yorickpeterse.com

51–60 of 165 posts

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

#51
post #40
post #32

Earlier quoted context omitted.

That's something like what Go does. Goroutines are "green threads" - they can be preempted. There's a CPU scheduler in user space. Go tries to provide "async" performance, and goroutines have minimal state. This seems to work well for the web server case. Pure "Async" means your application is now in the CPU dispatching business. This works well only if your application is totally I/O bound and has no substantial com…

> 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?

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

#52
This is extremely myopic. there is not a 1:1 correspondence between using asynchronous io and using one thread per file. Asynchronous io lets you dodge thread safety mechanisms like semaphores.

Not all of us are trying to write a webapp or whatever, some of us just need to load a lot of data from several descriptors without serializing all the blocking operations.

>Not every IO operation can be performed asynchronously though. File IO is perhaps the best example of this (at least on Linux). To handle such cases, languages must provide some sort of alternative strategy such as performing the work in a dedicated pool of OS threads.

Uhhh this is just wrong file io can definitely be done asynchronously, on Linux, and without language support.

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

#53
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…

With both synchronous and asynchronous flows, if you want to support cancelation from a high level (e.g. the user can click Cancel in the UI), you need to pass some kind of context from there down to each and every operation that needs to be cancellable. Whether that is done by passing around context objects from the UI down to IO operations, or by ensuring all functions called from the UI down return Task objects, the problem is the same. The context object approach even has the advantage that it also allows you to pass other application-specific things, such as passing progress information up from the bottom of the stack to the UI, or logging ids etc, that the generic Task object won't have.

Also, deadline-style contexts aren't as hard as you make them out to be: you keep track of the remaining time, and pass that as a timeout to every blocking operation, then subtract the actual time taken and pass the remaining time to the next blocking task etc. Or, you can do the exact same thing as the async case: you spawn two threads, one handling the blocking operations, the other waiting for a timeout, and both sharing a cancelation context. Whichever finishes first cancels the other.

The difficulty of doing cancellations for most real operations is anyway going to be much much higher than these small differences. The real difficulty of cancellations lies in undoing already finished parts of atomic operations that you completed. The effort to do that is going to dominate the effort to get pass down the context object.

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

#54
post #47
post #36

Earlier quoted context omitted.

> But at the programming language level the compiler does have insight into the dependencies of your continuation This is really the key point - coupled with the fact that certain I/O operations are just inherently asynchronous. The TX/RX queues in NICs are an async, message passing interface - regardless of whether you're polling descriptors or receiving completion interrupts. So really, async I/O is the natural abs…

> certain I/O operations are just inherently asynchronous. That's technically not true. The fact that its inherently async is an implementation detail. You either have blocking sync or non-blocking async. the implementation could be synchronous if the blocking didn't cause overhead and that was the proposed idea here - at least as far as I interpreted it.

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 inherently asynchronous hardware interface.

The software interfaces built on top of the inherently asynchronous hardware interface can either preserve or change that nature. That is a implementation detail.

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

#55
I don't quite agree with this piece, as it is comparing apples and oranges.

What you want is patterns for having safety, efficiency and maintainability for concurrent and parallelized processing.

One early pattern for doing that was codified as POSIX threads - continue the blocking processing patterns of POSIX so that you can have multiple parallelizable streams of execution with primitives to protect against simultaneous use of shared resources and data.

IO_URING is not such a pattern. It is a kernel API. You can try to use it directly, but you can also use it as one component in a userland thread systems, in actor systems, in structured concurrency systems, etc.

So the author is seemingly comparing the shipped pattern (threads) vs direct manipulation, and complaining that the direct manipulation isn't as safe or maintainable. It wasn't meant to be.

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

#56

I am not sure I buy the underlying idea behind this piece, that somehow a lot of money/time has been invested into asynchronous IO at the expense of thread performance (creation time, context switch time, scheduler efficiency, etc.). First, significant work has been done in the kernel in that area simply because any gains there massively impact application performance and energy efficiency, two things the big kernel…

Make os thread runs more efficient is like `faking async IOs (disk/network/whatever goes out from the computer shell) into the sync operations in a more efficient way`. But why would you do it at first place if the program can handle async operations at first place? Just let userland program do their business would be a better decision though.

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

#57

Synchronous IO has always been more efficient. Anyone that thought otherwise doesn't understand how complicated context switches are in CPUs. The benefit of async io has always been handling tons of idle connections.

You can perform all the I/O you want with 0 context switches today in Linux. Why would performing more context switches (e.g. to call read(2)) speed things up?

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

#59
It's not clear that context switches can be made sufficiently cheap on fast CPUs without disabling mitigations for side-channel attacks. So the idea of making OS threads comparably performant to goroutines, rust async, or any implementation of cooperative multithreading seems impractical.

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

#60
post #22
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…

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 rewrites and implicit state machines than thread based models. Java style or Go style green threads are much simpler frameworks than C#'s whole async task machinery, or even than Rust's Tokio.

And any program written as a series of threads running blocking operations with proper synchronization is also pretty easy to convert to an async model. The difficulty is taking a single-threaded program and making it run in an async model, but that is a completely different discussion.

However, I do agree that ultimately you do need the OS to provide async IO primitives to have efficient IO at the application level. Since OS threads can't scale to the required level, even the green threads + blocking IO approach is only realistically implementable with async IO from the OS level. This could change if the OS actually implemented a green threads runtime for blocking operations, but that might still have other inefficiencies related to costs of crossing security boundaries.

Post reply on HN