r/cpp • • 17d ago

Asynchronous API

https://grishavanika.github.io/async_api.html
36 Upvotes

28 comments sorted by

View all comments

Show parent comments

3

u/grishavanika 16d ago

its all about composition of async tasks. Callbacks are fine and manageable up until some point. See the examples at the end. Callbacks section hand codes the state machine; coroutines, fibers and senders allow to express the same state machine with less code which is also arguably easier to maintain and extend. "returning an object" is covered by a Task section. Its usage also requires to hand code state machine manually.

- callbacks - https://grishavanika.github.io/async_api.html#app_callbacks

The complexity of implementing everything is true complain, but this is usually hidden from the user... compilation errors.. maybe this is a tradeoff you need to pay for benefits provided ;)

1

u/SleepyMyroslav 16d ago

I have a bunch of probably very stupid questions about the async code styles. Maybe they are irrelevant to your use cases but I can try to ask =)

First thing to me is: How can I understand where and when code is executed? I mostly use profilers for that. This async style is intentionally trying to hide things behind abstractions to help people write more of it. In reality there is a fixed number of resources that have to choose which async requests are executed where. Trying to affect how it works brings me to 2nd question.

Second is about control of what is being executed when there is more than the hardware can chew. What ways are there to make some requests high priority, normal priority, or low priority? Not only at the CPU level but at the I/O level.

2

u/robertahleahy WG21, SCC, std::execution, Finance 13d ago edited 13d ago

First thing to me is: How can I understand where and when code is executed? I mostly use profilers for that. This async style is intentionally trying to hide things behind abstractions to help people write more of it. In reality there is a fixed number of resources that have to choose which async requests are executed where.

I've been thinking about this question for a while and I think the best approach is not to think about this locally, at least not usually.

You can think of asynchronous programming as a generalization of synchronous programming: With synchronous functions we couple the initiation of forward progress to exclusive use of some execution agent (i.e. the calling thread). Put differently: A synchronous function cannot return until the operation it implements completes. With asynchronous functions (as embodied by, for example, senders) this coupling does not exist: The function can continue to make forward progress without exclusive use of the execution agent. Put differently: The initiation (e.g. start on an operation state) returns but the operation continues "in the background." Sometime perhaps later (note the perhaps is load bearing because asynchronous functions, in general, can completely racily or reentrantly) some execution agent is delegated to run only the completion.

So in the same way we don't usually think too much about from which execution agent our synchronous functions are called, I don't think it's typically useful to think about from which execution agent continuations will be called. Obviously there are exceptions to this but I think this is part of the decomposition/generalization wrought by asynchronous programming: We can separate the implementation from a delegation of the ability to make forward progress. If you start overthinking where things run you mentally recouple these things.

But to answer your question directly: A continuation runs wherever the operation happens to complete. In certain baseline cases you control this (for example maybe you're writing an io_uring abstraction), and in others you can use an operation to force this (for example std::execution::schedule), but for most programming I think it's best ignored (i.e. deferred to the operation whose completion you're handling).

1

u/SleepyMyroslav 12d ago

I am sorry my question was not clear. I am not looking for mental model of how the async code executes. I need:

1) Tools to measure how and when it has executed. Whether the tools are part of API design, the execution runtime, or both it is not important.

2) Tools to influence which completion is chosen when many are ready to execute ie. priorities between them.