Live data from Hacker News

What async promised and what it delivered

causality.blog

151–160 of 317 posts

Re: What async promised and what it delivered

#151
post #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 byt…

Despite my panning of async elsewhere on this thread, I agree with you here. Embassy is a thing of beauty and a great use of Rust's async. Much of my embedded career was bogged down managing a pile of state machines. With async/await and embassy, that just goes away.

Re: What async promised and what it delivered

#152
I would point out two other short Cummings in the async/await paradigm

1. It makes asynchronous programming look synchronous. I do not like things being other than they appear. The point was touched on with the:

        getOrders(user.id),
        getRecommendations(user.id)
example, but it is a serious thing when the v mental model is wrong

2. On a related issue CPU bound code can block the thread of execution and stop any concurrency in its tracks

In Rust there is the added problem of shoehorning it into the memory model which has lead to a lot of hairy code and tortured paradigms (e.g. pin)

Re: What async promised and what it delivered

#153

I like async and await. I understand that some devs don’t want to learn async programming. It’s unintuitive and hard to learn. On the other hand I feel like saying “go bloody learn async, it’s awesome and massively rewarding”.

Or... we've learned it and don't like it? For legitimate reasons?

Re: What async promised and what it delivered

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

I do Rust without async and I'm happier for it.

But yes, once you go dining on other people's crates you definitely get the impression that you have to, because tokio gets its fingerprints all over everything.

But also there are non-thread stealing runtimes that don't require Send/Sync on the Future. Just nobody uses them.

Because Rust is the language that tokio ate.

Re: What async promised and what it delivered

#155

> OS threads are expensive: an operating system thread typically reserves a megabyte of stack space Why is reserving a megabyte of stack space "expensive"? > and takes roughly a millisecond to create I'm not sure where this number is from, it seems off by a few orders of magnitude. On Linux, thread creation is closer to 10 microseconds.

1 megabyte stacks mean ten thousand threads require 10 gigabytes of RAM just for the stacks. The entire point of the asynchronous programming paradigm is to reclaim all of those gigabytes by not allowing stacks to develop at all, by stealthily turning everything into a hidden form of cooperative multitasking instead.

Re: What async promised and what it delivered

#156
post #96
post #87

> Language designers who studied the async/await experience in other ecosystems concluded that the costs of function coloring outweigh the benefits and chose different paths. Not really. The author provides Go as evidence, but Go's CSP-based approach far predates the popularity of async/await. Meanwhile, Zig's approach still has function coloring, it's just that one color is "I/O function" and the other is "non-I/O f…

I mean Java's Loom feels like the 'ultimate' example of the latter for the _ordinary_ programmer, in that it effectively leaves you just doing what looks like completely normal threads however you so please, and it all 'just works'.

The initial Loom didn't really provide the semantics and ergonomics of async/await which is why they immediately started working on structured concurrency.

And for my money I prefer async/await to the structured concurrency stuff..

Re: What async promised and what it delivered

#157
post #110
post #106

Earlier quoted context omitted.

> Why is reserving a megabyte of stack space "expensive"? Because if you use one thread for each of your 10,000 idle sockets you will use 10GB to do nothing. So you'll want to use a better architecture such as a thread pool. And if you want your better architecture to be generic and ergonomic, you'll end up with async or green threads.

On a 64-bit system, 10 GB of address space is nothing.

10 GB of RAM is certainly something though. Especially in current times.

Re: What async promised and what it delivered

#158
post #137

Earlier quoted context omitted.

And it doesn't actually prevent concurrency.

Sure, but concurrent != parallel. You can't have data races with a single thread of execution - a while loop writing i=0 or i=1 on each iteration is not a data race. Two async functions doing so is not a data race either.

You should really look up the definition of race condition; it has nothing to do with parallel processing. Parallel processing just makes it harder to deal with.

Re: What async promised and what it delivered

#159

> OS threads are expensive: an operating system thread typically reserves a megabyte of stack space Why is reserving a megabyte of stack space "expensive"? > and takes roughly a millisecond to create I'm not sure where this number is from, it seems off by a few orders of magnitude. On Linux, thread creation is closer to 10 microseconds.

1 megabyte stacks mean ten thousand threads require 10 gigabytes of RAM just for the stacks . The entire point of the asynchronous programming paradigm is to reclaim all of those gigabytes by not allowing stacks to develop at all, by stealthily turning everything into a hidden form of cooperative multitasking instead.

Only if they're resident. Otherwise you just need one page per thread of physical memory (so ~40MB on x86) and 10GB of virtual memory.

Re: What async promised and what it delivered

#160
post #120

Earlier quoted context omitted.

> you will use 10GB to do nothing. You don't pay for stack space you don't use unless you disable overcommit. And if you disable overcommit on modern linux the machine will very quickly stop functioning.

The amount of stack you pay for on a thread is proportional to the maximum depth that the stack ever reached on the thread. Operating systems can grow the amount of real memory allocated to a thread, but never shrink it. It’s a programming model that has some really risky drawbacks.

> Operating systems can grow the amount of real memory allocated to a thread, but never shrink it.

Operating systems can shrink the memory usage of a stack.

  madvise(page, size, MADV_DONTNEED);
Leaves the memory mapping intact but the kernel frees underlying resources. Subsequent accesses get either new zero pages or the original file's pages.

Linux also supports mremap, which is essentially a kernel version of realloc. Supports growing and shrinking memory mappings.

  stack = mremap(stack, old_size, old_size / 2, MREMAP_MAYMOVE, 0);
Whether existing systems make use of this is another matter entirely. My language uses mremap for growth and shrinkage of stacks. C programs can't do it because pointers to stack allocated objects may exist.
Post reply on HN