Live data from Hacker News

What async promised and what it delivered

causality.blog

61–70 of 317 posts

Re: What async promised and what it delivered

#61
post #42

Async ruined Rust for me, even though I write exactly the kind of highly concurrent servers to which it's supposed to be perfectly suited. It degrades API surfaces to the worst case :Send+Sync+'static because APIs have to be prepared to run on multithreaded executors, and this infects your other Rust types and APIs because each of these async edges is effectively a black hole for the borrow checker. Don't get me star…

> It degrades API surfaces to the worst case :Send+Sync+'static because APIs have to be prepared to run on multithreaded executors

This isn't true at all. The Send+Sync+'static is basically the limitation of tokio::spawn

https://emschwartz.me/async-rust-can-be-a-pleasure-to-work-w...

Change the executor, and the bound changes.

Re: What async promised and what it delivered

#62
I will agree - async rust on an operating system isn’t all that impressive - it’s a lot easier to just have well defined tasks and manually spawn threads to do the work.

However, in embedded rust async functions are amazing! Combine it with a scheduler like rtic or embassy, and now hardware abstractions are completely taken care of. Serial port? Just two layers of abstraction and you have a DMA system that shoves bytes out UART as fast as you can create them. And your terminal thread will only occupy as much time as it needs to generate the bytes and spit them out, no spin locking or waiting for a status register to report ready.

Re: What async promised and what it delivered

#63
post #58

Earlier quoted context omitted.

“Function coloring” is an imaginary issue in the first place. Or rather it's a real phenomenon, but absolutely not limited to async and people don't seem to care about it at all except when talking about async. Take Rust: you return `Result ` , you are coloring your function the same way as you are when using `async` . Same for Option. Errors as return values in Go: again, function coloring. One of your nested functi…

Function coloring does not mean that functions take parameters and have return values. Result is not a color. You can call a function that returns a Result from any other function. Errors as return values do not color a function, they're just return values. Async functions are colored because they force a change in the rest of the call stack, not just the caller. If you have a function nested ten levels deep and it c…

You can exit an async/IO monad just like you can exit an error monad: you have a thread blocking run(task) that actually executes everything until the future resolves. Some runtimes have separate blocking threadpools so you don't stall other tasks.

Re: What async promised and what it delivered

#64
post #50

Earlier quoted context omitted.

I'm not sure this is correct mental model of what async solves Async precisely improves disk/network I/O-bound applications because synchronous code has to waste a whole thread sitting around waiting for an I/O response (each with its own stack memory and scheduler overhead), and in something like an application server there will be many incoming requests doing so in parallel. Cancellation is also easier with async C…

I read this argument ("async is for I/O-bound applications") often, but it makes no sense to me. If your app is I/O bound, how does reducing the work the (already idling!) CPU has to spend on context switching improve the performance of the system?

The simplest example is that you can easily be wasteful in your use of threads. If you just write blocking code, you will block the thread while waiting on io, and threads are a finite resource.

So avoiding that would mean a server can handle more traffic before running into limits based on thread count.

Re: What async promised and what it delivered

#65
post #47

Earlier quoted context omitted.

async/await came out of C# (well at least the JS version of it). There are a bunch of use cases for it outside of implementing concurrency in a single threaded runtime. Pretty much every GUI toolkit I've ever used was single threaded event loop/GUI updates. Green threads are a very controversial design choice that even JVM backed out of.

> Green threads are a very controversial design choice that even JVM backed out of. Did they? Project Loom has stabilized around Java 21, no?

I stand corrected, I stopped keeping track of JVM years ago, was referring to initial green threads implementation.

Re: What async promised and what it delivered

#66
post #7
post #5

Earlier quoted context omitted.

It is a tool. Some tools make you more productive after you have learned how to use them. I find it interesting how in software, I repeatedly hear people saying "I should not have to learn, it should all be intuitive". In every other field, it is a given that experts are experts because they learned first.

Except you're hearing it from someone who doesn't have a problem handling state machines and epoll and manual thread management.

Right but how do you expose your state machine and epoll logic to callers? As a blocking function? As a function that accepts continuations and runs on its own thread? Or with no interface such that anyone who wants to interoperate with you has to modify your state machine?

Re: What async promised and what it delivered

#67

Async is a Javascript hack that inexplicably got ported to other languages that didn't need it. The issue arose because Javascript didn't have threads, and processing events from the DOM is naturally event driven. To be fair, it's a rare person who can deal with the concurrency issues threads introduce, but the separate stacks threads provide a huge boon. They allow you to turn event driven code into sequential code.…

> And as for Rust - that's beyond inexplicable. Rust has green threads in the early days and abandoned them in favour of async / await.

There was a fair bit of time between the two, to the point I'm not sure the latter can be called much of a strong motivation for the former. Green threads were removed pre-1.0 by the end of 2014 [0], while work on async/await proper started around 2017/2018 [1].

In addition, I think the decision to remove green threads might be less inexplicable than you might otherwise expect if you consider how Rust's chosen niche changed pre-1.0. Off the top of my head no obligatory runtime and no FFI/embeddability penalties are the big ones.

> Rust now has a green thread implementation that fixes that mistake

As part of the runtime/stdlib or as a third-party library?

[0]: https://github.com/rust-lang/rust/issues/17325

[1]: https://without.boats/blog/why-async-rust/

Re: What async promised and what it delivered

#68
No mention of JVM.. which is a bit odd as recently is kinda solved this problem. Sure, not all use cases, but a lot.

It uses N:M threading model - where N virtual threads are mapped to M system threads and its all hidden away from you.

All the other languages just leak their abstractions to you, java quietly doesn't.

Sure, java is kinda ugly language, you can use a different JVM language, all good.

Don't get me wrong, love python, rust, dart etc, but JVM is nice for this.

Re: What async promised and what it delivered

#69
post #50

Earlier quoted context omitted.

I read this argument ("async is for I/O-bound applications") often, but it makes no sense to me. If your app is I/O bound, how does reducing the work the (already idling!) CPU has to spend on context switching improve the performance of the system?

It sounds like you're assuming both pieces are running on the same server, which may not be the case (and if you're bottlenecked on the database it probably shouldn't be, because you'd want to move that work off the struggling database server) Assuming for the sake of argument that they are together, you're still saving stack memory for every thread that isn't created. In fact you could say it allows the CPU to be id…

Right, I think the argument should be that transitioning from a synchronous to asynchronous programming model can improve the performance of a previously CPU/Memory-bound system so that it saturates the IO interface.

Re: What async promised and what it delivered

#70

Earlier quoted context omitted.

I wish the “Function coloring” meme died. It made sense in the context of the original blog post (which was about callback hell, hence the “4. Red functions are more painful to call” section un the original blog post), but doesn't make sense in the context of async/await. There's literally nothing special with async, it's just an effect among many others. As soon as you start using function arguments instead of using…

I think the lesson is to be careful about introducing incompatibility via the type system. When you introduce distinctions, you reduce compatibility. Often that’s deliberate (two functions shouldn’t be interchangeable because it introduces a bug) but the result is lots of incompatible code, and, often, duplicate code. Effects are another way of making functions incompatible, for better or worse. It can be done badly.…

You can also use type inference with union types like ZIO. So you could e.g. return a Result where the error type is `DatabaseError | InvalidBirthdayError`. If you're in an error monad anyway, and you add a new error type deep in the call stack, it can just infer itself into the union up the stack to wherever you want to handle it.
Post reply on HN