News for hackers. Stuff that matters.
Re:How to think about `async`/`await` in Rust by flohofwoe on Wednesday July 05, 2023 @05:11AM (#36597769)
> Threads are a resource hog.

Not really on any decent operating system, but if they are too heavy, there's still fibers aka green-threads aka stack-switching (which at least on Windows are an operating system primitive - but can be implemented in user code on any system that gives you direct access to the CPU stack and registers).

I doubt that the resulting async-await state machine code which 'slices' sequential functions into many small parts which are then jumped in and out frequently is any better for performance than stack-switching (in async/await you still need to switch a 'context pointer' on entry/exit instead of the stack pointer).

One obvious advantage of the state-machine code transformation is that it also works in very limited single-threaded runtime environments without control over the callstack (like WASM).

In any case, from the user perspective, async/await should just be language syntax sugar, how it is implemented under the hood ideally shouldn't matter (e.g. it should also be possible to implement it on top of a task scheduler that runs on fibers or threads instead of a state-machine code transformation).

Re:How to think about `async`/`await` in Rust by gpderetta on Wednesday July 05, 2023 @06:11AM (#36598229)
The async/await model gives you exactly one guarantee: because the yield continuation is second class, at most one stack frame can be suspended, so the the amount of space that needs to be reserved for a task is bounded and potentially can be computed statically. This can be important for very high performance/very high concurrency programs, so I think the upsides can be more than the downsides in something like rust, C++ [1], and possibly C#. I still do not understand why async was deemed appropriate, for example, in python.

As an aside, there is a lot of confusion in this thread between general async operations and async/await.

[1] but of course C++ screwed it up by requiring hard to remove allocations.

Re:How to think about `async`/`await` in Rust by versteegen on Wednesday July 05, 2023 @06:55AM (#36598539)
> I still do not understand why async was deemed appropriate, for example, in python.

My best guess is that it's because of implementation limitations in CPython and likely other interpreters. StacklessPython is a fork of CPython with real coroutines/fibers/green threads but apparently they didn't want to merge that patch. Very disappointing, because async/await is a nearly useless substitute for my desired usecase (embedded scripting languages with pauseable scripts).

Re:How to think about `async`/`await` in Rust by gpderetta on Wednesday July 05, 2023 @07:02AM (#36598608)
There is also gevent which is a library only coroutine extension which didn't require any changes to the interpreter itself. I'm also sure it would be easier to maintain and evolve if it was part of python core.
Re:How to think about `async`/`await` in Rust by Spivak on Wednesday July 05, 2023 @02:22PM (#36604778)
> I still do not understand why async was deemed appropriate, for example, in python.

Because queues backed by thread/process pools for serving web requests has sharp edges.

Re:How to think about `async`/`await` in Rust by miki123211 on Wednesday July 05, 2023 @06:58AM (#36598560)
Userspace fibers (no clue about Windows fibers) still have the blocking IO problem. If your fiber calls read() but there's no data and read blocks for a few minutes, until the next message is received, no other fibers can be scheduled on that thread in the meantime. With async, the task just gets suspended, something like epoll gets called with info about all the suspended tasks, and the thread unblocks once any task can move forward, not necessarily the one that requested the read. This problem doesn't exist if your pseudo threads have first-class language and runtime support, see goroutines for example.
Re:How to think about `async`/`await` in Rust by flohofwoe on Wednesday July 05, 2023 @07:02AM (#36598609)
If the blocking function would be fiber-aware, and yield execution back to the fiber runtime until the (underlying) async operation has completed, it would "just work". One could most likely write their own wrapper functions which use the Windows "overlapping IO" functions (those just have a completion callback if I remember right - PS or maybe completion Event?)

Not possible with the C stdlib IO functions though (that's why it would be nice to have optional async IO functions with completion callback in the C stdlib)

PS: just calling a blocking read in async/await code would have the same effect though, you need an "async/await aware" version of read()

Re:How to think about `async`/`await` in Rust by gpderetta on Wednesday July 05, 2023 @07:09AM (#36598656)
if your async task performs a raw read it also will block. In the coroutine case you of course need to call a read wrapper that allows for user mode scheduling. That can literally be the same function you use for async. Coroutines also allow library interposition tricks that transparently swap a blocking read with one that returns control to the event loop, so in principle existing blocking code need not change. Libpth did something like that for example. YMMV.