[boost.async] Seeking Endorsement
Dear fellow Boost developers, I am seeking endorsement for my C++20 async coroutine library boost.async. It provides coroutine primitives & utilities that are easy to use and intuitive, to anyone who has seen python's asyncio or javascripts async/await APIs before. It simplifies using asio and increases compile times significantly by encouraging the usage of translations units. The features include: - coroutine types (eager, lazy, generators) - built-in cancellation - synchronization of multiple coroutines (select, gather, join) - channels - with (an async scope akin to python's with expression) - asio integration, i.e. completion tokens I think this kind of library is much needed in boost and the wider C++ community. code: https://github.com/klemens-morgenstern/async docs: https://klemens.dev/async/
I take it that you meant to say “decreases” compile times? I’m happy to endorse this library for review. I think the utilities are sorely needed to simplify asynchronous programming in C++. On Mon, 24 Jul 2023 at 06:32, Klemens Morgenstern via Boost < boost@lists.boost.org> wrote:
Dear fellow Boost developers,
I am seeking endorsement for my C++20 async coroutine library boost.async.
It provides coroutine primitives & utilities that are easy to use and intuitive, to anyone who has seen python's asyncio or javascripts async/await APIs before.
It simplifies using asio and increases compile times significantly by encouraging the usage of translations units. The features include:
- coroutine types (eager, lazy, generators) - built-in cancellation - synchronization of multiple coroutines (select, gather, join) - channels - with (an async scope akin to python's with expression) - asio integration, i.e. completion tokens
I think this kind of library is much needed in boost and the wider C++ community.
code: https://github.com/klemens-morgenstern/async docs: https://klemens.dev/async/
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Richard Hodges hodges.r@gmail.com office: +44 2032 898 513 home: +376 861 195 mobile: +376 380 212
Yes, it decreases compile times. I must have thought "increases build speed" or something like that when typing. On Mon, Jul 24, 2023 at 12:39 PM Richard Hodges via Boost < boost@lists.boost.org> wrote:
I take it that you meant to say “decreases” compile times?
I’m happy to endorse this library for review. I think the utilities are sorely needed to simplify asynchronous programming in C++.
On Mon, 24 Jul 2023 at 06:32, Klemens Morgenstern via Boost < boost@lists.boost.org> wrote:
Dear fellow Boost developers,
I am seeking endorsement for my C++20 async coroutine library boost.async.
It provides coroutine primitives & utilities that are easy to use and intuitive, to anyone who has seen python's asyncio or javascripts async/await APIs before.
It simplifies using asio and increases compile times significantly by encouraging the usage of translations units. The features include:
- coroutine types (eager, lazy, generators) - built-in cancellation - synchronization of multiple coroutines (select, gather, join) - channels - with (an async scope akin to python's with expression) - asio integration, i.e. completion tokens
I think this kind of library is much needed in boost and the wider C++ community.
code: https://github.com/klemens-morgenstern/async docs: https://klemens.dev/async/
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Richard Hodges hodges.r@gmail.com office: +44 2032 898 513 home: +376 861 195 mobile: +376 380 212
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Hi all,
We need this. You have my endorsement.
Regards,
Ruben.
On Mon, 24 Jul 2023 at 15:29, Marcelo Zimbres Silva via Boost
On Mon, 24 Jul 2023 at 06:32, Klemens Morgenstern via Boost
wrote: Dear fellow Boost developers,
I am seeking endorsement for my C++20 async coroutine library boost.async.
<snip>
Hi, you have my endorsement.
Regards, Marcelo
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
No and no. They're asynchronous, which means they're able to co_await asynchronous tasks such as an async_read, and thus need an event loop (e.g. asio::io_context). The C++23 generators are synchronous and thus are a different category and thus would not fit this library. On Mon, Jul 24, 2023 at 11:33 PM Phil Endecott via Boost < boost@lists.boost.org> wrote:
Klemens Morgenstern wrote:
I am seeking endorsement for my C++20 async coroutine library boost.async.
- coroutine types (eager, lazy, generators)
Can the generators be used without ASIO? Are they compatible the the C++23 std::generator?
Regards, Phil.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Dear all, quick reminder to adhere to the ML rules [1] and refrain from top-posting and over-quoting. The email quoted below is a good example why we have those rules: a) It is not immediately clear to what the "no" refers to b) quoting the quoted parts doesn't help in understanding, so those could be omitted Note: I picked that EMail as a random example, it could have been any other as well, so it's not particularly about this but just as I noted an increased amount of top-posting and over-quoting recently. So please just take this as a reminder to improve the experience on the ML. Thanks, Alex [1] https://www.boost.org/community/policy.html
No and no.
They're asynchronous, which means they're able to co_await asynchronous tasks such as an async_read, and thus need an event loop (e.g. asio::io_context).
The C++23 generators are synchronous and thus are a different category and thus would not fit this library.
On Mon, Jul 24, 2023 at 11:33 PM Phil Endecott via Boost < boost@lists.boost.org> wrote:
Klemens Morgenstern wrote:
I am seeking endorsement for my C++20 async coroutine library boost.async.
- coroutine types (eager, lazy, generators) Can the generators be used without ASIO? Are they compatible the the C++23 std::generator?
Regards, Phil.
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
On 24/07/2023 15:51, Phil Endecott via Boost wrote:
Klemens Morgenstern wrote:
I am seeking endorsement for my C++20 async coroutine library boost.async.
- coroutine types (eager, lazy, generators)
Can the generators be used without ASIO? Are they compatible the the C++23 std::generator?
His library works without effort with all third party awaitables. This is a very big thing, previously using C++ coroutines with ASIO meant you had to use ASIO's awaitables and couldn't use any others. With this library, you can mix and match any type of awaitable freely with ASIO code. That's an enormous leap forward in C++ coroutine usability. I'll be review managing it we currently think between the 8th and 18th of August. Niall
Because my code relies heavily on asio's spawn() could you provide examples using spawn() in the git repo?
How does boost.async integrate boost.process? I'm especially interested in adync. reading/writing from/to forked process' stdin/stout/stderr.
Oliver
24.07.2023 18:59:47 Niall Douglas via Boost
On 24/07/2023 15:51, Phil Endecott via Boost wrote:
Klemens Morgenstern wrote:
I am seeking endorsement for my C++20 async coroutine library boost.async.
- coroutine types (eager, lazy, generators)
Can the generators be used without ASIO? Are they compatible the the C++23 std::generator?
His library works without effort with all third party awaitables. This is a very big thing, previously using C++ coroutines with ASIO meant you had to use ASIO's awaitables and couldn't use any others. With this library, you can mix and match any type of awaitable freely with ASIO code. That's an enormous leap forward in C++ coroutine usability.
I'll be review managing it we currently think between the 8th and 18th of August.
Niall
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Do you mean asio::spawn with async? "co_await asio::spawn(co_await async::this_coro::executor, my_stackful_coro, async::use_op)" would do. It can handle any async operation, of which asio::spawn is one. There is no integration between boost.context and async (and there can't be, I think). I wonder if there could be a faux-routine, that looks like a async-coro, but is actually a boost.context primitive underneath. Boost.async integrates with everything asio, through the use_op completion token, so you can just use it with boost.process (v2 would be recommended) like this: That could look akin to this: promise<void> pipe_reader(asio::readable_pipe & pr) { std::string buffer; buffer.resize(4096); std::size_t n = co_await pr.async_read_some(asio::buffer(buffer), async::use_op); // do something with the data pr.close(); } namespace vs = boost::process::v2; asio::readable_pipe rp{co_await async::this_coro::executor}; v2::process proc(co_await async::this_coro::executor, "/usr/bin/cat", {"source.txt"}, bind_stdio{.stdout=rp}); co_await async::join(pipe_reader(rp), proc.async_wait(async::use_op)); On Tue, Jul 25, 2023 at 12:22 PM oliver.kowalke--- via Boost < boost@lists.boost.org> wrote:
Because my code relies heavily on asio's spawn() could you provide examples using spawn() in the git repo?
How does boost.async integrate boost.process? I'm especially interested in adync. reading/writing from/to forked process' stdin/stout/stderr.
Oliver
24.07.2023 18:59:47 Niall Douglas via Boost
: On 24/07/2023 15:51, Phil Endecott via Boost wrote:
Klemens Morgenstern wrote:
I am seeking endorsement for my C++20 async coroutine library boost.async.
- coroutine types (eager, lazy, generators)
Can the generators be used without ASIO? Are they compatible the the C++23 std::generator?
His library works without effort with all third party awaitables. This is a very big thing, previously using C++ coroutines with ASIO meant you had to use ASIO's awaitables and couldn't use any others. With this library, you can mix and match any type of awaitable freely with ASIO code. That's an enormous leap forward in C++ coroutine usability.
I'll be review managing it we currently think between the 8th and 18th of August.
Niall
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
So I just checked the faux-routine and it's possible, but pretty pointless (just brings overhead for a bit of syntactic sugar). You can use `co_await asio::spawn(exec, stackful_coro, async::use_op)` into the asio stackful coros and then `async::spawn(exec, async_coro, yield_context)` to go the other way. I think the asio completion-token API is perfect for this and also works fine with asio::awaitable. On Tue, Jul 25, 2023 at 1:09 PM Klemens Morgenstern < klemensdavidmorgenstern@gmail.com> wrote:
Do you mean asio::spawn with async? "co_await asio::spawn(co_await async::this_coro::executor, my_stackful_coro, async::use_op)" would do. It can handle any async operation, of which asio::spawn is one.
There is no integration between boost.context and async (and there can't be, I think). I wonder if there could be a faux-routine, that looks like a async-coro, but is actually a boost.context primitive underneath.
Boost.async integrates with everything asio, through the use_op completion token, so you can just use it with boost.process (v2 would be recommended) like this:
That could look akin to this:
promise<void> pipe_reader(asio::readable_pipe & pr) { std::string buffer; buffer.resize(4096); std::size_t n = co_await pr.async_read_some(asio::buffer(buffer), async::use_op); // do something with the data pr.close(); }
namespace vs = boost::process::v2; asio::readable_pipe rp{co_await async::this_coro::executor}; v2::process proc(co_await async::this_coro::executor, "/usr/bin/cat", {"source.txt"}, bind_stdio{.stdout=rp}); co_await async::join(pipe_reader(rp), proc.async_wait(async::use_op));
On Tue, Jul 25, 2023 at 12:22 PM oliver.kowalke--- via Boost < boost@lists.boost.org> wrote:
Because my code relies heavily on asio's spawn() could you provide examples using spawn() in the git repo?
How does boost.async integrate boost.process? I'm especially interested in adync. reading/writing from/to forked process' stdin/stout/stderr.
Oliver
24.07.2023 18:59:47 Niall Douglas via Boost
: On 24/07/2023 15:51, Phil Endecott via Boost wrote:
Klemens Morgenstern wrote:
I am seeking endorsement for my C++20 async coroutine library boost.async.
- coroutine types (eager, lazy, generators)
Can the generators be used without ASIO? Are they compatible the the C++23 std::generator?
His library works without effort with all third party awaitables. This is a very big thing, previously using C++ coroutines with ASIO meant you had to use ASIO's awaitables and couldn't use any others. With this library, you can mix and match any type of awaitable freely with ASIO code. That's an enormous leap forward in C++ coroutine usability.
I'll be review managing it we currently think between the 8th and 18th of August.
Niall
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
AFAIK, boost::asio::spawn() already uses boost.context internally (stackful coroutines).
So I was curious how it works with co_await as you mentioned in your post
25.07.2023 07:10:24 Klemens Morgenstern via Boost
Do you mean asio::spawn with async? "co_await asio::spawn(co_await async::this_coro::executor, my_stackful_coro, async::use_op)" would do. It can handle any async operation, of which asio::spawn is one.
There is no integration between boost.context and async (and there can't be, I think). I wonder if there could be a faux-routine, that looks like a async-coro, but is actually a boost.context primitive underneath.
Boost.async integrates with everything asio, through the use_op completion token, so you can just use it with boost.process (v2 would be recommended) like this:
That could look akin to this:
promise<void> pipe_reader(asio::readable_pipe & pr) { std::string buffer; buffer.resize(4096); std::size_t n = co_await pr.async_read_some(asio::buffer(buffer), async::use_op); // do something with the data pr.close(); }
namespace vs = boost::process::v2; asio::readable_pipe rp{co_await async::this_coro::executor}; v2::process proc(co_await async::this_coro::executor, "/usr/bin/cat", {"source.txt"}, bind_stdio{.stdout=rp}); co_await async::join(pipe_reader(rp), proc.async_wait(async::use_op));
On Tue, Jul 25, 2023 at 12:22 PM oliver.kowalke--- via Boost < boost@lists.boost.org> wrote:
Because my code relies heavily on asio's spawn() could you provide examples using spawn() in the git repo?
How does boost.async integrate boost.process? I'm especially interested in adync. reading/writing from/to forked process' stdin/stout/stderr.
Oliver
24.07.2023 18:59:47 Niall Douglas via Boost
: On 24/07/2023 15:51, Phil Endecott via Boost wrote:
Klemens Morgenstern wrote:
I am seeking endorsement for my C++20 async coroutine library boost.async.
- coroutine types (eager, lazy, generators)
Can the generators be used without ASIO? Are they compatible the the C++23 std::generator?
His library works without effort with all third party awaitables. This is a very big thing, previously using C++ coroutines with ASIO meant you had to use ASIO's awaitables and couldn't use any others. With this library, you can mix and match any type of awaitable freely with ASIO code. That's an enormous leap forward in C++ coroutine usability.
I'll be review managing it we currently think between the 8th and 18th of August.
Niall
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Ah, seems like this is an Asio library? I think I was expecting something like runtime-agnostic coroutine primitives that users could use to easily build their own coroutines. Maybe even adding something like cppcoro's `task<T>` which is far and away the best user-facing task implementation I've seen. Whatever happened to the Requests library that was being worked on? We should be reviewing that library instead of an Asio wrapper. - Christian
On Tue, Jul 25, 2023, 10:42 PM Christian Mazakas via Boost < boost@lists.boost.org> wrote:
Ah, seems like this is an Asio library?
It is not. It is a coroutine library that uses asio for it's event loop.
I think I was expecting something like runtime-agnostic coroutine primitives that users could use to easily build their own coroutines.
Why would users want to so that? The building blocks are present, but i donl not understand why so many coroutine types would be needed.
Maybe even adding something like cppcoro's `task<T>` which is far and away the best user-facing task implementation I've seen.
Async has a task<T>.
Whatever happened to the Requests library that was being worked on? We should be reviewing that library instead of an Asio wrapper.
Not if we want users. Coroutines ate much more relevant at this time.
- Christian
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
On Tue, Jul 25, 2023 at 8:15 AM Klemens Morgenstern via Boost
Not if we want users. Coroutines ate much more relevant at this time.
How many users does this proposed boost.async have? I would like to see evidence of at least minimal adoption outside the Boost mailing list bubble before giving an endorsement. Thanks
On Tue, 25 Jul 2023 at 17:54, Vinnie Falco via Boost
How many users does this proposed boost.async have? I would like to see evidence of at least minimal adoption outside the Boost mailing list bubble before giving an endorsement.
I am writing a new project with it. I know of one other who has also decided to. The async primitives made available by this library makes this a logical, and pleasant-to-implement choice. Previously building an asio-based project was a labour of love.
Thanks
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
On Tue, Jul 25, 2023 at 9:00 AM Richard Hodges via Boost
The async primitives made available by this library makes this a logical, and pleasant-to-implement choice.
I can't speak to that because I have not used the library. And my evaluation process considers more than the statements from one or two individuals. I like to see it in an actual library or program whose source code is published, where the author is accessible and I can ask them questions about their experience with it. Thanks
How many users does this proposed boost.async have? I would like to see evidence of at least minimal adoption outside the Boost mailing list bubble before giving an endorsement.
I got 32 stars on the repo without doing any advertising and two active users (outside boost I think) that opened issues. Not that much, but it's far from an established library. Note that there's currently a real gap in the C++ library landscape. We got coroutines standardized, but using them isn't trivial for various reasons. This library provides a solution to that, because the standard won't. I've been using asio awaitables for years mrself and have written & seen the interest in asio::experimental::coro. Not to mention how popular similar libraries are in other The review process will establish if this is the correct approach for boost, but I have few doubts that a generic, asynchronous C++20 coroutine library has a market. And it'll provide functionality that should be in the standard, just like boost did before 2011.
Not if we want users. Coroutines ate much more relevant at this time.
The problem is, this definitely isn't true. Users already have Asio's `use_awaitable`. A coroutine library that uses Asio as its event loop is basically a lateral move from, well, just using Asio with `co_spawn` and `use_awaitable`. Not like I wanna veer off too far into the weeds here about Requests vs whatever. But I really don't think coroutines are much more relevant than a robust HTTP client that's written using Asio's coroutines today. But I feel like I have a better understanding of the library now and its goals.
And it'll provide functionality that should be in the standard, just like boost did before 2011.
The problem is, this also isn't true. This kind of functionality should never touch the standard because it ties a coroutine to an execution context. In fact, I'd argue this library's biggest mistake is doing exactly that. What I'm thinking of is something like cppcoro's task type, a task type that can only be co_await'd by a parent coroutine. To this end, `cppcoro::task<T>` can appear in interfaces and then runtime authors are free to invoke this via their own runtime-specific coroutine types. cppcoro's task stores the type-erased coroutine_handle when it's transformed into an awaitable so it works with all parent coroutine types. I think we need vocabulary types like that, with schedulers set alongside them. It worries me to see an executor directly tied to a coroutine when it's really not required, let alone purported that this should actually be a standardized practice. There's definitely room for innovation in the coroutine space but it's hard to argue for a "coroutine library" that I can't even use without bringing in Asio. - Christian
On Tue, 25 Jul 2023 at 20:32, Christian Mazakas via Boost < boost@lists.boost.org> wrote:
Not if we want users. Coroutines ate much more relevant at this time.
The problem is, this definitely isn't true.
Users already have Asio's `use_awaitable`. A coroutine library that uses Asio as its event loop is basically a lateral move from, well, just using Asio with `co_spawn` and `use_awaitable`.
Asio’s primitives are incomplete. I say this as a fan of asio.
Not like I wanna veer off too far into the weeds here about Requests vs whatever. But I really don't think coroutines are much more relevant than a robust HTTP client that's written using Asio's coroutines today.
I believe Klemens is quite far into requests but on that journey it became apparent that primitives were needed to make async IO and coroutines inter operate nicely. I have been on the same journey and came to the same conclusion.
But I feel like I have a better understanding of the library now and its goals.
And it'll provide functionality that should be in the standard, just like boost did before 2011.
The problem is, this also isn't true.
This kind of functionality should never touch the standard because it ties a coroutine to an execution context. In fact, I'd argue this library's biggest mistake is doing exactly that.
Respectfully you are wrong about this. Every implementation of coroutines and IO centres around an implicit or explicit IO dispatch loop. Python, JavaScript, asio, etc. this is because you can’t do async IO without an IO loop. Asio abstracts the native IO loop on each target.
What I'm thinking of is something like cppcoro's task type, a task type that can only be co_await'd by a parent coroutine. To this end, `cppcoro::task<T>` can appear in interfaces and then runtime authors are free to invoke this via their own runtime-specific coroutine types. cppcoro's task stores the type-erased coroutine_handle when it's transformed into an awaitable so it works with all parent coroutine types.
C++ lacks out of the box utility. This library has made firm choices about interface design and implantation in order to provide that out of box experience without the landmine experience, while still allowing customisation by experts.
I think we need vocabulary types like that, with schedulers set alongside them. It worries me to see an executor directly tied to a coroutine when it's really not required, let alone purported that this should actually be a standardized practice. There's definitely room for innovation in the coroutine space but it's hard to argue for a "coroutine library" that I can't even use without bringing in Asio.
If you’re using boost, asio is free. The library requires a tiny subset of ASIO, and optionally allows the author to work with all of asio and any asio-compatible library, seamlessly. And incidentally with better performance than ASIO coroutines, either stackless or stackfull. Tying executors to coroutines is absolutely necessary unless you want users to have to contend with thread synchronisation or jitter manually. This library takes all these concerns away.
- Christian
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Richard Hodges hodges.r@gmail.com office: +44 2032 898 513 home: +376 861 195 mobile: +376 380 212
On Wed, Jul 26, 2023 at 2:32 AM Christian Mazakas via Boost
Not if we want users. Coroutines ate much more relevant at this time.
The problem is, this definitely isn't true.
Users already have Asio's `use_awaitable`. A coroutine library that uses Asio as its event loop is basically a lateral move from, well, just using Asio with `co_spawn` and `use_awaitable`.
Asio's awaitable are not anywhere near a complete coroutine library. They are (by design) meant to work within asio to compose async operations in a specific way. You can't "escape" awaitables, i.e. you can't co_await anything else than an asio::awaitable. This was one of the reasons I wrote experimental::coro (that can co_yield) and now you got two, and since chris addred co_compose three different coroutine types that can't efficiently interact with each other.
This kind of functionality should never touch the standard because it ties a coroutine to an execution context. In fact, I'd argue this library's biggest mistake is doing exactly that.
It's a mistake shared by all asynchronous coroutine libraries. It's unavoidable. It would be possible for async to provide it's own type erased type for the scheduler. But that would effectively be reimplementing asio::any_io_executor in immature form, for the great gain that we don't need to include one header from another boost library. I did really consider that, but since any_io_executor allows me to do that already, I fail to see the point.
What I'm thinking of is something like cppcoro's task type, a task type that can only be co_await'd by a parent coroutine. To this end, `cppcoro::task<T>` can appear in interfaces and then runtime authors are free to invoke this via their own runtime-specific coroutine types. cppcoro's task stores the type-erased coroutine_handle when it's transformed into an awaitable so it works with all parent coroutine types.
That is what async does.
I think we need vocabulary types like that, with schedulers set alongside them. It worries me to see an executor directly tied to a coroutine when it's really not required, let alone purported that this should actually be a standardized practice. There's definitely room for innovation in the coroutine space but it's hard to argue for a "coroutine library" that I can't even use without bringing in Asio.
It is required as soon as you write asynchronous code that does multiple things at once. async brings in the executor part of async, so it doesn't need to create it's own, like cppcoro does for example. In that case I reproduced well-tested & seasoned code from asio with my own greenfield impl to avoid an include of a header that's already present (because boost) for an immature implementation that's almost the same while losing the easy usability with boost.beast, boost.process, boost.mysql & boost.redis. I know you want to use io_uring and you seem to think you can't. What's the issue with creating your own awaitables that use io_uring and co_await them from async's coroutines?
I know you want to use io_uring and you seem to think you can't. What's the issue with creating your own awaitables that use io_uring and co_await them from async's coroutines?
Actually, this would be a great test. I tried reading the docs but I'm not sure how to actually author this. So, Async runs in its own event loop. In this case, I want a separate thread with its own io_uring event loop. Something simple that basically just calls: while(true) { io_uring_wait_cqe( ... ); Unfortunately, this means I now _have_ to introduce thread synchronization latency when I'd like to use my own event loop here. Aside from that, I can write an awaitable that communicates with the io_uring context in the awaitable's `await_suspend` but I'm not sure how to get Async to know when to resume the awaiting coroutine. What would I wind up doing here? On my end, a completion queue event (CQE) comes in, I recognize it's associated with Async and now I want to tell Async to resume the awaiting coroutine, i.e. call `.resume()` on the associated `coroutine_handle`. - Christian
On Wed, 26 Jul 2023 at 17:25, Christian Mazakas via Boost < boost@lists.boost.org> wrote:
I know you want to use io_uring and you seem to think you can't. What's the issue with creating your own awaitables that use io_uring and co_await them from async's coroutines?
Actually, this would be a great test.
I tried reading the docs but I'm not sure how to actually author this.
You don't need to. Chris has already built io_uring support into ASIO. simply compile with *-DBOOST_ASIO_HAS_IO_URING_AS_DEFAULT* Effect: *Linux: io_uring is used instead of epoll.* See: https://www.boost.org/doc/libs/1_82_0/doc/html/boost_asio/using.html
On Wed, Jul 26, 2023 at 11:25 PM Christian Mazakas via Boost
I know you want to use io_uring and you seem to think you can't. What's the issue with creating your own awaitables that use io_uring and co_await them from async's coroutines?
Actually, this would be a great test.
See what richard said: you can have asio run on io_uring already. You can then
I tried reading the docs but I'm not sure how to actually author this.
So, Async runs in its own event loop. In this case, I want a separate thread with its own io_uring event loop. Something simple that basically just calls:
while(true) { io_uring_wait_cqe( ... );
Unfortunately, this means I now _have_ to introduce thread synchronization latency when I'd like to use my own event loop here.
If you want to use your own event loop, you can write an executor for it, too. Richard layed that out here: https://cppalliance.org/richard/2020/10/31/RichardsOctoberUpdate.html This will still use asio::any_io_executor which will incur a runtime overhead since it's type erased. I have put a global `executor` type into async, so that you can replace this ( see here) https://github.com/klemens-morgenstern/async/blob/master/include/boost/async... but I don't know what a good solution (i.e. acceptable for boost) is to allow a user to get his own type alias in there, because he'll need an include.
Aside from that, I can write an awaitable that communicates with the io_uring context in the awaitable's `await_suspend` but I'm not sure how to get Async to know when to resume the awaiting coroutine. What would I wind up doing here?
Most likely UB. The await_suspend(std::coroutine_handle<T> h) can however grab the executor from the promise, by calling h.promise().get_executor() (after checking with a requires statement) if you need to post back.
See what richard said: you can have asio run on io_uring already. You can then
The problem is, this gets said a lot but no one really understands it. There's a lot to benefit from io_uring that Asio simply can't support so saying that "Asio can use io_uring" is technically true but it's largely disingenuous because it neglects all the good parts of io_uring that _can't_ be used. I don't wanna derail the conversation with all those details but I can expand upon this if required.
If you want to use your own event loop, you can write an executor for it, too.
I see. Is this as a replacement for the one used internally by Async?
Most likely UB. The await_suspend(std::coroutine_handle<T> h) can however grab the executor from the promise, by calling h.promise().get_executor() (after checking with a requires statement) if you need to post back.
Why would this be UB? - Christian
On Fri, Jul 28, 2023 at 12:15 AM Christian Mazakas via Boost
See what richard said: you can have asio run on io_uring already. You can then
The problem is, this gets said a lot but no one really understands it.
There's a lot to benefit from io_uring that Asio simply can't support so saying that "Asio can use io_uring" is technically true but it's largely disingenuous because it neglects all the good parts of io_uring that _can't_ be used. I don't wanna derail the conversation with all those details but I can expand upon this if required.
Did you look into whether or not you can do that with asio, by reducing the asio::io_context to just wait for events? And then initiating all the rest manually. That'd work for async.
If you want to use your own event loop, you can write an executor for it, too.
I see. Is this as a replacement for the one used internally by Async?
Async needs an executor to use for dispatch & post. Atm the type defaults to any_io_executor (which is a type erased wrapper). If you want to change the type we should figure out a solution, it's possible from my end. I.e. the config.hpp defines an executor type alias that gets used everywhere, which could be changed to something else. I just don't know how to handle includes in the config in a way acceptable for boost.
Most likely UB. The await_suspend(std::coroutine_handle<T> h) can however grab the executor from the promise, by calling h.promise().get_executor() (after checking with a requires statement) if you need to post back.
Why would this be UB?
Because you'll run thread unsafe code on two threads then. It *shuold* be fine if you got a single coroutine stack, but once you select(coro1, coro2) and both resume on different threads you'll have UB.
I think I may've misunderstood everything. I was under the impression that Async could support custom awaitables but I don't believe it can. Or at least, I'd need to see an actual example of this being authored. Purport that I wanted to author an awaitable that spawned work on a thread pool in its `await_suspend()` method. Do I just use the awaiting coro's executor to post() back to Async's event loop? What should I actually be posting back? Just a simple callable that invokes `h.resume()`? - Christian
On Fri, Jul 28, 2023 at 1:04 AM Christian Mazakas via Boost
I think I may've misunderstood everything.
I was under the impression that Async could support custom awaitables but I don't believe it can.
It definitely can.
Or at least, I'd need to see an actual example of this being authored.
Sure, I probably need to add some example of multi-threading support.
Purport that I wanted to author an awaitable that spawned work on a thread pool in its `await_suspend()` method. Do I just use the awaiting coro's executor to post() back to Async's event loop? What should I actually be posting back? Just a simple callable that invokes `h.resume()`?
Yes. You need to resume the awaiting coroutine on the thread that called await_resume, and you'd usually do that through posting to it's executor. Technically you can just post the coroutine handle as it has an operator().
Yes. You need to resume the awaiting coroutine on the thread that called await_resume, and you'd usually do that through posting to it's executor.
Alright, I think a good next step would be formalizing this in the library then. We can go ahead and call this kind of abstraction Waker or something to that effect. And then ideally this is featured in the docs. Formalizing this Waker mechanism has the benefit that the user doesn't have to think about the lifetime of the awaiting coroutine. Because Async seems to support cancellation, the awaiting coroutine can be cancelled and destroyed before the external work `post()`s the `coroutine_handle` for execution. Naively calling `.resume()` is unsafe without some form of guarantee around lifetime. - Christian
On Fri, Jul 28, 2023 at 3:05 AM Christian Mazakas via Boost
Yes. You need to resume the awaiting coroutine on the thread that called await_resume, and you'd usually do that through posting to it's executor.
Alright, I think a good next step would be formalizing this in the library then.
It's documented and formalized (https://klemens.dev/async/#associators).
We can go ahead and call this kind of abstraction Waker or something to that effect.
And then ideally this is featured in the docs.
Formalizing this Waker mechanism has the benefit that the user doesn't have to think about the lifetime of the awaiting coroutine. Because Async seems to support cancellation, the awaiting coroutine can be cancelled and destroyed before the external work `post()`s the `coroutine_handle` for execution. Naively calling `.resume()` is unsafe without some form of guarantee around lifetime.
Cancellation is a signal that you can connect to (get_cancellation_slot on the promise). It won't itself destroy the coro or anything like that. The ownership of the awaiter gets transferred to the awaitee, thus calling resume is guaranteed to work if you don't call destroy on the coroutine_handle. Likewise it's legal to destroy it, which will unwind the whole stack of coroutines.
Hi Klemens, Thank you for the proposal. I endorse it. Best, Em seg., 24 de jul. de 2023 às 01:32, Klemens Morgenstern via Boost < boost@lists.boost.org> escreveu:
Dear fellow Boost developers,
I am seeking endorsement for my C++20 async coroutine library boost.async.
It provides coroutine primitives & utilities that are easy to use and intuitive, to anyone who has seen python's asyncio or javascripts async/await APIs before.
It simplifies using asio and increases compile times significantly by encouraging the usage of translations units. The features include:
- coroutine types (eager, lazy, generators) - built-in cancellation - synchronization of multiple coroutines (select, gather, join) - channels - with (an async scope akin to python's with expression) - asio integration, i.e. completion tokens
I think this kind of library is much needed in boost and the wider C++ community.
code: https://github.com/klemens-morgenstern/async docs: https://klemens.dev/async/
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Alan Freitas https://alandefreitas.github.io/alandefreitas/ https://github.com/alandefreitas
participants (11)
-
Alan de Freitas
-
Alexander Grund
-
Christian Mazakas
-
Klemens Morgenstern
-
Marcelo Zimbres Silva
-
Niall Douglas
-
oliver.kowalke@gmail.com
-
Phil Endecott
-
Richard Hodges
-
Ruben Perez
-
Vinnie Falco