-
-
Notifications
You must be signed in to change notification settings - Fork 396
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
Single threaded runtime support #1681
Comments
Where do you see that? There are several examples of quinn on tokio's single-threaded mode in this repo alone. |
For example, AsyncUdpSocket requires Send+Sync but nothing about Glommio nor monio is Send + Sync. Am I missing something? |
Also, could you point me at the single-threaded mode examples? My grep is failing me but I may be looking for the wrong thing. |
That allows Quinn to support multithreaded runtimes. It does not require them.
Tokio calls its single-threaded mode the "current thread" runtime. Grep for |
I must be missing something. When I go to add glommio.rs in the runtime/ folder, the build fails saying that Glommio’s UDP socket struct doesn’t implement Send+Sync as required by the AsyncUdpSocket trait. Sync is “solvable” through gratuitous Arc+Mutex wrappers, but send isn’t (eg Glommio has an Rc within it’s UdpSocket class). I think Tokio’s single threaded runtime might still export Send+Sync for its various classes to avoid duplication which is why tokio works. But I don’t see how the Runtime and AsyncUdpSocket traits having Send+Sync don’t infect into requiring runtime implementations to expose Send+Sync types too. |
Whether a runtime is multithreaded is, as you can see from tokio, a separate concern from whether its I/O primitives are |
So the other problem is I hadn't realized that quinn makes direct networking syscalls instead of dispatching to the underlying socket implementation. That means that it's incompatible with completion based I/O (#915) which is what glommio is so I'm going to stop this experiment for now. |
Quinn dispatches through a |
Quinn itself invokes blocking syscalls directly on the socket if you're using `udp::UdpSocketState`. That negates
the entire point of using a completion based layer (unless you bypass . I think the Runtime
abstractions would have to change substantially to delegate I/O operations
to the AsyncUdpSocket itself among other changes (as the other thread
points out, unless the author is mistaken, there’s a bunch of inherent
additional memcpy operations taking place which again negates the point of
using something like io_uring).
Are you saying that a completion-based layer should duplicate the logic of udp::UdpSocketState?
|
@vlovich are you looking at a release or the main branch? IIRC the hierarchy of the trait etc was refactored substantially after the last release. |
This is incorrect. Quinn performs no blocking I/O on any
You can implement |
Sorry. I was imprecise. It makes syscalls directly on the socket which makes the complexity of implementing a completion-based API much harder. |
Again, quinn does not issue syscalls directly. All I/O is mediated through |
Let’s say I have an async fn called send. To implement poll_send does that mean I have to box the future for a send and keep it alive until the poll resolves? Is there a reason it’s implemented as a poll interface instead of an async fn that could potentially avoid the need for boxing of futures? |
If your future is
Yes; |
That's actually supposed to be stabilized next month according to https://blog.rust-lang.org/inside-rust/2023/05/03/stabilizing-async-fn-in-trait.html and the target stabilization date according to https://releases.rs/docs/1.74.0/.
I think Pin<&mut self> would actually go a long way because then I can do a poll_send into the specific UdpSocket implementation and avoid the need for bridging polling code with async. Would you be open to this change? |
Without trait object support. The workaround or this is the same thing you have to do today, and the same thing that eventual native support will probably be sugar for: boxing. A polling API will probably remain more efficient, as it can box once internally rather than on every call.
I'm interested in it, since we'll never move these values around after polling anyway, but changing from
|
I am generally interested in using alternative runtimes like glomio myself, so I am supportive in general of improving the situation. I will have to take a closer look at our code, but I believe the important piece will be habing the same for send and recv. |
Looking at the current abstraction of The challenge is that when trying to tie them in some form together, you run into the issue of non object safe traits (both with generics and associated types on the |
We could also make it so that the Runtime is exclusively responsible for producing the dyn AsyncUdpSockets, I suppose? |
Yes, so far I only got a version which adds two generics to almost all structs in Looking at improving the situation around |
It is not necessary to produce |
@vlovich, it sounds like @dignifiedquire doesn't have an objection to tweaking |
Yes, it would just be much nicer if we could use this cool type system to express this 😓 |
Closing as non-actionable, since single-threaded runtime support was never missing and tangential discussion has wrapped up. Feel free to open a PR for |
Perusing the implementation, I see that there's a baked in assumption of a work-stealing async runtime. Would there be any interest in having a feature flag that supports a single-threaded (e.g. tokio rt, glommio, monoio, etc) async runtimes? I imagine primarily that will involve dropping the requirement for Send for Runtime futures, replacing Arc with Rc, Mutex with a RefCell, etc).
The text was updated successfully, but these errors were encountered: