async claims to:
- not have a stack
- gets converted to fixed size state machines
yet async fns can call async fns / regular fns; how is this possible without a stack of some form ?
async claims to:
yet async fns can call async fns / regular fns; how is this possible without a stack of some form ?
Async functions can't be directly recursive - this is a compile error:
pub async fn recursive() {
recursive().await;
}
error[E0733]: recursion in an `async fn` requires boxing
--> src/lib.rs:1:26
|
1 | pub async fn recursive() {
| ^ recursive `async fn`
|
= note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
= note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
Ah, so is the argument:
we don't care about a stack of regular fns because the stack has to unwind to a fixed size before we hit an .await
for async fns, they have to form a dag
therefore, although the stack can grow arbitrarily during the execution of an async fn, by the time it hits an .await
, it is back to fixed size ?
Yes, except the requirement is even stronger: at point where you call await
nothing is left on the stack.
That's the key to asynchronous execution: when async
function is actually running β it borrows stack from the current thread and thus can use synchronous functions.
But at the point where you can βcallβ await
nothing is left on that stack, all the state is moved to pinned Future thus stack can be returned to Executor.
When Executor gives the async
function a chance to continue (maybe on the same thread, maybe on the other thread) it lends stack again β but it must be freed before next await
can be called.
This explanation should be enough for you to understand how and when you may call await
and what's allowed and what's not allowed for async
functions 99% of time.
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.