-
Notifications
You must be signed in to change notification settings - Fork 186
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
(Is there already) support for async stream #586
Comments
Also if not, should it be built in a way that it interoperates with |
Hi @georgikoyrushki95, I was able to wrap a I don't think it makes sense to add that particular Stream type to Unifex because we intend to be free of dependencies, but a type that's analogous to |
@ispeters thanks so much! This is exactly what I'm looking for!
For this, do you mean a libunifex-specific async generator and adapting that to a stream? Basically identical to what you have done in your godbolt, the only difference being we add the equivalent of Or do you want the stream to be backed by "pure" senders? Both would work for us & it appears it'd be equivalent for the consumers of the stream values. The difference would be in how the values are produced, I guess. Let me know your thoughts, I think this is something I'm interested to contribute :) |
@georgikoyrushki95, I think a coroutine-based async sequence and a "raw sender"-based one would serve different needs and offer different trade-offs so, if I get to be greedy, I want both. Our experience at Meta has been that coroutines are easier to read, write, debug, and just generally maintain than composition-of-sender algorithms-style code. The cost of that ease is basically overhead; coroutines don't optimize as well as raw senders (either for size or speed). The advice we give to internal teams adopting Unifex is that they should prefer coroutines until they know that the overheads are unacceptable, at which point they can refactor to the lower-level abstraction of raw senders. My ideal coroutine-based async sequence that's analogous to
I'm not sure what an ideal sender-based Stream would look like; I kind of suspect there's room for several different implementations. @janondrusek plans to upstream an internal type that's currently named
|
Hey, so I have been looking into this over the past couple of days. Wanted to double-check something with you on the expected scheduler affinity of the void foo()
{
// assume thread where foo() executes is thread id == 0
static unifex::single_thread_context genCtx; // assume thread id == 1
auto generator = []() -> async_generator<int> {
std::cout << "thread id before scheduling =" << std::this_thread::get_id() << std::endl; // prints 0
co_await unifex::schedule(genCtx.get_scheduler());
std::cout << "thread id after scheduling=" << std::this_thread::get_id() << std::endl; // prints 1
for(int i = 0; i < 5; ++i) {
co_yield i;
std::cout << "thread id after resuming gen =" << std::this_thread::get_id() << std::endl; // always prints 1
}
}();
auto result = bexsr::sync_wait([&generator]() -> task<int> {
int sum = 0;
for (auto itr = co_await generator.begin(); itr != generator.end(); co_await ++itr) {
std::cout << "thread id in the outer task =" << std::this_thread::get_id() << std::endl; // always prints 0
sum += *itr;
}
co_return sum;
}());
// do something with result
} In essence, when the generator resumes, we always switch onto the latest thread it was scheduled on? And if that's the case, where would it be a good place to do the switch? My thinking is within the generator's |
Really nice! Thanks for sharing this example. |
Sorry for the delayed response; holiday PTO and performance review season have me inundated. The short reply is that I think we need to provide the semantics @georgikoyrushki95 described in his example code—I think anything else would violate the principle of least surprise. One thing: I think it was a mistake to make
If I've understood the coroutine spec correctly, Without having tried to implement a generator like this before, I suspect you'll need to enforce the scheduler affinity invariant in the I think the way to build "reschedule on each resumption" is to write a little custom receiver that resumes the generator in |
Hi, I also commented on #507 as it seems related (at least to someone not too familiar with S/R yet).
A little bit of context of what I want: I am looking for something that represents an async stream, to sketch out an example:
Is this something that the generic
range_stream
would support OR we need to build our own stream adapter? And isn't this something generic enough to be present inlibunifex
? Basically something likecppcoro::async_generator
that speaks the stream protocol? I have seencppcoro::async_generator
being mentioned in the docs, but wasn't able to find anything that can support that functionality here.The text was updated successfully, but these errors were encountered: