You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If a coroutine wants to return the value of another task as its result then you currently need to co_await the other task first and then co_return the result of that. eg.
lazy_task<T> foo(int n);
lazy_task<T> bar()
{
co_returnco_awaitfoo(123);
}
task_task<> usage()
{
lazy_task<T> t = bar();
T result = co_await t;
}
However, this means that the coroutine frame of bar() remains alive until foo() completes as the bar() coroutine is registered as the continuation of the foo() task.
If the coroutine frame of bar() is large then this means we're not releasing the memory/resources of the bar coroutine frame as soon as we could which can lead to additional memory pressure in applications.
It is also potentially problematic for recursive tasks where the recursion depth could be arbitrarily deep, the memory consumption of the call chain could be unbounded.
It would be nice if instead we could perform a tail-recursion here by using co_return task instead of co_return co_await task. This would effectively have the semantics of moving the returned task into the lazy_task<T> object that is being awaited at the top of the call chain. ie. that the result of the returned task becomes the result of the current coroutine.
This would allow the current coroutine frame to be freed before resuming the returned task. This means that in a purely-tail-recursive set of tasks that we'd have at most 2 coroutine frames in existence at one time, even if the recursion had unbounded depth.
eg.
lazy_task<T> foo();
lazy_task<T> bar()
{
co_returnfoo(123); // Don't co_await foo() task before returning.
}
task_task<> usage()
{
lazy_task<T> t = bar();
T result = co_await t;
}
The co_return foo(123); statement basically moves the lazy_task<T> value returned by foo() call into the t local variable being awaited in usage(). This frees the bar() coroutine frame before then resuming the foo() coroutine.
The text was updated successfully, but these errors were encountered:
Note that until we have access to the coroutine_handle<> await_suspend(coroutine_handle<> h) overload that guarantees tail-recursive resumption of another coroutine after suspending the current coroutine, the recursive invocation of nested coroutines may still consume some space on the regular stack, even if the resources used by coroutine frames are cleaned up eagerly.
We won't be able to implement this for lazy_task<void> yet, however, since the current coroutines TS disallows mixing return_void() and return_value() in the same promise_type.
If a coroutine wants to return the value of another task as its result then you currently need to
co_await
the other task first and thenco_return
the result of that. eg.However, this means that the coroutine frame of
bar()
remains alive untilfoo()
completes as thebar()
coroutine is registered as the continuation of thefoo()
task.If the coroutine frame of
bar()
is large then this means we're not releasing the memory/resources of the bar coroutine frame as soon as we could which can lead to additional memory pressure in applications.It is also potentially problematic for recursive tasks where the recursion depth could be arbitrarily deep, the memory consumption of the call chain could be unbounded.
It would be nice if instead we could perform a tail-recursion here by using
co_return task
instead ofco_return co_await task
. This would effectively have the semantics of moving the returned task into thelazy_task<T>
object that is being awaited at the top of the call chain. ie. that the result of the returned task becomes the result of the current coroutine.This would allow the current coroutine frame to be freed before resuming the returned task. This means that in a purely-tail-recursive set of tasks that we'd have at most 2 coroutine frames in existence at one time, even if the recursion had unbounded depth.
eg.
The
co_return foo(123);
statement basically moves thelazy_task<T>
value returned byfoo()
call into thet
local variable being awaited inusage()
. This frees thebar()
coroutine frame before then resuming thefoo()
coroutine.The text was updated successfully, but these errors were encountered: