Skip to content
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 async/await compatible with io_uring (Linux async io)? #60589

Closed
rektide opened this issue May 6, 2019 · 7 comments

Comments

Projects
None yet
4 participants
@rektide
Copy link

commented May 6, 2019

Hello all. On Linux, we're getting a new high performance async io implementation called io_uring. I'm curious how Rust is going to be able to interface with this, & how is this going to work with Rust's async/await plans?

I'm afraid my knowledge of Rust's async/await isn't up to par to do much guesswork for how Linux's async io would fit into Rust's async language features. I'm hoping someone around these parts might be willing to take a look & report back with your thoughts on feasibility, and how Rust might leverage Linux's high performance async io mechanism.

The maintainer @axboe also has a very nice PDF write-up of io_ring (which he announced here). From the intro:

We'll go over the reasons for its existence, inner workings of it, and the user visible interface.

@lambda

This comment has been minimized.

Copy link
Contributor

commented May 6, 2019

Rust's async/await is a language feature which makes it easy to indicate points during which computation will suspend while waiting for some kind of result, and then resume later once that result is ready. It allows you to do this in a very low-overhead way at the language level.

However, it isn't tied to any particular operating system or method of delivering notifications of completion of asynchronous events. That is handled by a futures executor, which handles dispatching to the appropriate code to run when notified that I/O is ready.

So as long as there is an executor written which is capable of doing I/O via io_uring, you should be able to write asynchronous code which will execute on such an executor. I am not aware if there are are any executors yet which support io_uring, but it would be possible to write them.

@rektide

This comment has been minimized.

Copy link
Author

commented May 6, 2019

I am not aware if there are are any executors yet which support io_uring, but it would be possible to write them.

Is this ThreadPool (also here atm) an example of one of those executors? I'm surprised to find that there's no trait Executor implemented here, nor can I find a definition an Executor trait. I'm not sure I'm looking in the right place. Can you please kindly help me get on the right page?

@lambda

This comment has been minimized.

Copy link
Contributor

commented May 6, 2019

The Rust async ecosystem is a little confusing right now, as it has been rapidly evolving.

There is some custom syntax in the language itself, plus a few traits that need to be provided by the standard library to interact with this syntax and provide the common core functionality.

Then there is the futures crate, which provides a lot of extra utilities on top of that core functionality, as well as a thread-pool based executor for executing tasks asynchronously. It provides traits for asynchronous I/O, but doesn't provide any implementation of those traits, except for some trivial std types like Cursor for which reads and writes always return immediately and don't block.

If you want event-driven I/O, there is a third party crate, Tokio, which has its own executor and a Reactor which provides the core event loop for event-driven I/O, and then runs the computations that were awaiting the I/O results using its thread-pool based Executor. The actual underlying event loop is built on top of mio, a library which abstracts over the different event-driven I/O APIs of various platforms.

To summarize:

  • The compiler will have support for async/await syntax which allows functions to be written which can be suspended when waiting for I/O or any other task that might happen asynchronously, like a computation happening in another thread, and later resumed, in a very lightweight way
  • std will contain some of the core types needed for the ecosystem to operate
  • futures contains a number of useful utilities, and some traits representing abstract concepts like asynchronous I/O, but doesn't provide a way to actually do asynchronous I/O
  • tokio is currently the de-facto standard crate for doing event-driven, asynchronous I/O
  • mio is the low level crate providing abstraction over different types of event loops on different platforms

One thing to note is that io_uring is actually intended as a new interface for asynchronous disk I/O on Linux, which hasn't had a good asynchronous API so far. mio has so far avoided providing abstractions over asynchronous disk I/O, in part because there is no standard interface for it, and there have been a number of pitfalls in the existing asynchronous disk I/O interfaces on major platforms like Linux which make it not actually always asynchronous (some operations can block when you don't expect it), so disk I/O has generally be handled by a thread pool. Tokio provides some utilities for doing filesystem operations in a thread pool, but they're a bit limited.

io_uring will allow for proper asynchronous disk I/O on Linux, though just for a single file; other operations like walking the filesystem and opening files still use the normal blocking interfaces. Whether support for this gets added to mio or another crate is a matter of design, as well as whether it gets added to Tokio's current reactor or there are separate reactors for network and disk I/O. But it should be entirely possible to extend Tokio's reactor, or write your own reactor, which uses io_uring for disk I/O.

io_uring has been designed to be a flexible interface, so it should be able to support more than just disk I/O. I couldn't tell from the current docs if it currently does, or if that's intended to be a possible future addition.

@rektide

This comment has been minimized.

Copy link
Author

commented May 6, 2019

Amazing answer @lambda. Thank you, & well- I'm sorry for using so much of your time!!! That's amazingly comprehensive & well linked, thank you.

I'd asked some follow-up questions in #wg-async-foundation, and wanted to share some of the learning resources I found there too. Nemo157 pointed me at juliex & romio as other simpler examples that parallel what Tokio does, but at a little closer to my level. They've been helpful in understanding how executors & wakers relate to each other & function- something Tokio seems to make more formal with it's Reactor mechanism. I'm also finding @-withoutboat's Wake API I: what does a waker do? to be helpful in understanding how a basic implementation might function.

Last, I happened across the stdweb executor, which is interesting in that it's intended for running in webassembly. Not relevant to io_uring, but a good example of how different & varied executors/wakers/tasks might be.

@lambda

This comment has been minimized.

Copy link
Contributor

commented May 6, 2019

Ah, great, glad to hear you were able to get some other references.

Yeah, I pointed you to a lot of the full-featured, complex, fairly mature projects, but those other links you got are a lot better for learning how the ecosystem works.

@cramertj

This comment has been minimized.

Copy link
Member

commented May 7, 2019

Closing as resolved.

@cramertj cramertj closed this May 7, 2019

@rektide

This comment has been minimized.

Copy link
Author

commented May 8, 2019

Thanks all.
Adding one last comment just to make some additional keywords searchable: uring, liburing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.