Closed nazar-pc closed 1 year ago
Even something as simple as using FuturesUnordered
combinator with a bunch of async reads doesn't seem to work.
futures channels should be used inside the same runtime. You're using the sender and receiver in different threads. That seems a bug because the waker won't wake up the driver.
And what do you mean about FuturesUnordered
?
futures channels should be used inside the same runtime
Not at all. Channels can and often do exist in other threads, let alone runtimes, as long as the channel implementation is Send
. Try swapping compio::runtime::block_on
with futures::executor::block_on
or virtually anything else.
And what do you mean about FuturesUnordered?
I was creating FuturesUnordered
with a bunch of tasks that all do file.read_exact_at
to run all of them concurrently and then tried to drive them with compio
, but I believe the root issue is the same.
The root issue may not be the same. Would you provide an MLE of the FuturesUnordered
issue?
Happened in bigger app, can't reproduce with smaller example, ignore it for now.
OK, so this issue tracks about the futures channel issue. I think there are 3 solutions:
Event
insider the waker.schedule
and notify the driver.Futures channels should work with any runtime. I tried a simple example to test waker and it does seem to work properly:
So I'm not sure what is wrong with channel usage specifically :thinking:
The answer is simple: the waker doesn't wake up the driver, e.g. io-uring. The driver is still waiting for an operation to complete.
Another problem is that our Waker
is not safe to send to another thread. We may need to redesign some part to support your multi-threading case.
If you just want to notify a thread from another thread, EventHandle
is what you want; if you would like a multi-threading pool, compio-dispatch
provides a producer-consumer model.
This issue is far from easy to solve. I'll mark it with help-wanted
label.
Another problem is that our Waker is not safe to send to another thread. We may need to redesign some part to support your multi-threading case.
Why not? If it wasn't, it would not implement Send
and safe Rust wouldn't compile, right? :thinking:
Waker
implements Send
in std. If it's designed by us, we won't implement it:)
If you implement std::future::Future
you must use std::task::Waker
, I do not understand what you mean by "we won't implement it".
The runtime assumes single thread everywhere. It won't be easy to make the waker Send
, especially to wake one driver from another thread.
I'll open a PR to try to make the waker Send
later. Then we can see how to notify the driver.
Well, if it is supposed to be Send
, but you decided to not do that, then implementation must be unsound. That is kind of the point of Rust, to make unsound things fail to compile. But I'm not very knowledgable on such low level, so I'm only commenting on abstract level.
Well, if it is supposed to be
Send
, but you decided to not do that, then implementation must be unsound.
Not necessarily. It just means without careful handling, it's most likely unsound. But if we do make guarantee, then it's safe to work with. And that's the kind of the point of unsafe
. For now we're thinking unsafe impl Send
but check for thread id at runtime each time the waker is waked, thus forbidden cross thread access.
As you can imagine it will not be uncommon to use anything async other than compio's APIs in a typical application:
However, in case of
compio
unless anythingio_uring
-related is happening, it just hangs:This is certainly unexpected and I think should be fixed, otherwise it is painful and less performant to combine compio with anything async at all since
io_uring
is not the only reason async task could be polled. Looks like waker handling is broken/missing right now.