Boost logo

Boost :

From: Klemens Morgenstern (klemensdavidmorgenstern_at_[hidden])
Date: 2023-08-13 08:49:28


On Sun, Aug 13, 2023 at 3:46 PM Marcelo Zimbres Silva via Boost
<boost_at_[hidden]> wrote:
>
> Hi, this is my review of the proposed Boost.Async. Before I issue my
> final decision (ACCEPT/REJECT) I would like to ask the author some
> questions.

Thanks for the review and letting me address those questions first!

>
> Q1: Default completion token for other Boost libraries
> ================================================================
>
> I guess it will be a very common thing for all apps using Boost.Async
> to have to change the default completion token to use_op or use_task.
> Like you do in the examples
>
> > using tcp_acceptor = async::use_op_t::as_default_on_t<tcp::acceptor>;
> > using tcp_socket = async::use_op_t::as_default_on_t<tcp::socket>;
>
> Could this be provided automatically, at least for other Boost
> libraries? I know this would be a lot of work, but it would make user
> code less verbose and users would not have to face the token concept
> at first.

If could be, but I am also experimenting with how an async.io library
could look.
I.e. one that is async only (co_await stream.read()) and banished the
asio complexity
to the translations units. You can look at my experiments here
https://github.com/klemens-morgenstern/async/pull/8

>
> Q2: Lazy vs Eager
> ================================================================
>
> > It’s an eager coroutine and recommended as the default;
>
> Great, we can experiment with eagerness and laziness. But why is an
> eager coroutine recommended as default?

Because that's usually what I would want. If I have a coroutine
`async_do_the_thing()`
I would expect it to do the thing even if I don't await the result.
I think this is intuitive especially for those unfamiliar with asio.

>
> Q3: async_ready looks great
> ================================================================
>
> > We can however implement our own ops, that can also utilize the
> > async_ready optimization. To leverage this coroutine feature, async
> > provides an easy way to create a skipable operation:
>
> I think I have a use case for this feature: My first implementation of
> the RESP3 parser for Boost.Redis was based on Asio's async_read_until,
> which like every Asio async function, calls completion as if by post.
> The cost of this design is however high in situations where the next
> \r\n delimiter is already in the buffer when async_read_until is
> called again. The resulting rescheduling with post is actually
> unnecessary and greatly impacts performance, being able to skip the
> post has performance benefits. But what does *an easy way to create a
> skipable operation* actually mean? Does it
>
> - avoid a suspension point?
> - avoid a post?
> - act like a regular function call?

Theren are two mechanisms at work here:

   - if you provide a ready() function in a custom op, it will avoid
suspension altogether, thus be like a normal function call
   - if immediate completion is awaitable, the coroutine will suspend,
but resume rightaway. Thus avoid a post.

>
> Q4: Synchronization primitives
> ================================================================
>
> Will this library ever add synchronization primitives like async
> mutexes, condition variables, barriers etc. Or are they supposed to be
> used from an external library like proposed Boost.Sem.

It has channels that can do the mutex & barrier.
I don't like using names like mutex et al., because they imply they're
thread safe.
Since async is single-threaded you can actually use std::mutex if you
need to cross threads btw.

If we only have one mechanism, channels are the most versatile,
but I think there is indeed a need for something condition variable like.
I just don't know what it is yet, I am thinking maybe a pub/sub utility,
like a multicast-channel or something might do the trick.

I would however like to base this on user experience.
The channel model has proven itself in other languages, so I am
confident enough.

>
> Q5: Boost.Async vs Boost.Asio
> ================================================================
>
> I use C++20 coroutines whenever I can but know very little about their
> implementation. They just seem to work in Asio and look very flexible
> with use_awaitable, deferred, use_promise and use_coro. What advantage
> will Boost.Async bring over using plain Asio in regards to coroutine?

It's open to any awaitable, i.e. a user can just co_await whatever he wants.
asio prevents this by design because it has way less it can assume
about the environment.
That is, asio::awaitable cannot await anything other than itself and
an async op, not even asio::experimental::coro.

Furthermore all of those are meant for potentially threaded
environment so everything they do needs to be an async_op,
i.e. operator|| internally does multiple co_spawns through a `parallel_group`.

Because async can assume more things about how it's run, it can
provide a loss-less select, which `operator||` cannot do.

Likewise the channels work (mostly) without post, because they just
switch from one coro to the other,
whereas asio's channels need to use posting etc.

So in short: it's more efficient because it's optimized for single
threaded environments
it gives you better synchronization mechanisms and better extensibility.

I don't see the asio coroutines as competition, they just solve a
different use-case.
If you were to ask me which to use in boost.redis, I'd tell you to go
for asio's.
But if you wanted to write a small chat server based on boost
libraries, I'd recommend async.

>
> NOTE1
> ================================================================
>
> > Please state your experience with C++ coroutines and ASIO in your
> > review, and how many hours you spent on the review.
>
> I have spent a bit more than a day reading the docs, writing the
> review and integrating Boost.Redis.
>
> My experience with C++20 coroutines is limited to using them with Asio.
>
> I would also like to thank Klemens for submitting Boost.Async and
> Niall for offering to be its review manager.
>
> Marcelo
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk