c++ - co_await appears to be suboptimal? -
i have async function
void async_foo(a& a, b& b, c&c, function<void(x&, y&)> callback);
i want use in stackless coroutine write
auto coro_foo(a& a, b& b, c& c, x& x) /* -> y */ { struct awaitable { bool await_ready() const noexcept { return false; } bool await_suspend(coroutine_handle<> h) { async_foo(*a_, *b_, *c_, [this, h](x& x, y& y){ *x_ = std::move(x); y_ = std::move(y); h.resume(); }); } y await_resume() { return std::move(y); } a* a_; b* b_; c* c_; x* x_; y y_; }; return awaitable{&a, &b, &c, &x}; }
then can use this:
y y = co_await coro_foo(a, b, c, x);
and compiler rewrite this:
auto e = coro_foo(a, b, c, x); if (!e.await_ready()) { <suspend> if (e.await_suspend(h)) return; resume-point: <resume> } y y = e.await_resume();
with this, coroutine keep a_
, b_
, , c_
when it's suspended, when have keep them until coroutine_handle
in await_suspend(h)
.
(btw i'm not sure if can keep references arguments here.)
it more efficient if wrapper function directly coroutine_handle
argument.
it implicit argument:
promise f(coroutine_handle<> h); co_await f();
or special keyword-argument:
promise f(coroutine_handle<> h); f(co_await);
am missing here? (other overhead not big.)
the "coroutine" system defined coroutine ts designed handle asynchronous functions which:
- return future-like object (an object represents delayed return value).
- the future-like object has ability associated continuation function.
async_foo
doesn't fulfill these requirements. doesn't return future-like object; "returns" value via continuation function. , continuation passed parameter, rather being object's return type.
by time co_await
happens @ all, potentially asynchronous process generated future expected have started. or @ least, co_await
machinery makes possible have started.
your proposed version loses out on await_ready
feature, allows co_await
handle potentially-asynchronous processes. between time future generated , await_ready
called, process may have finished. if has, there no need schedule resumption of coroutine. should therefore happen right here, on thread.
if minor stack inefficiency bothers you, have things way coroutine ts wants to.
the general way handle coro_foo
directly execute async_foo
, return future-like object .then
-like mechanism. problem async_foo
doesn't have .then
-like mechanism, have create one.
that means coro_foo
must pass async_foo
functor stores coroutine_handle<>
, 1 can updated future's continuation mechanism. of course, you'll need synchronization primitives. if handle has been initialized time functor has been executed, functor calls it, resuming coroutine. if functor completes without resuming coroutine, functor set variable let await machinery know value ready.
since handle , variable shared between await machinery , functor, you'll need ensure synchronization between two. that's complex thing, it's whatever .then
-style machinery requires.
or live minor inefficiency.
Comments
Post a Comment