I have experience with the non-blocking IO library epoll
and its high level abstraction libuv
, so when I started learning Rust, I looked for Rust equivalents and found Mio. Mio works the way I understand about non-blocking IO and is familiar to me. I can easily use this kind of API to build high performance server applications using several threads or even a single thread.
Rust 1.39 brought the async
/ await
syntax. I have read some articles and documentation on it and it feels like coroutines. I understand that .await
can be used to yield CPU to do other things in the same thread, but there is no easy way to dynamically schedule code to run in that thread, it doesn't work in an evented way like epoll
, with which I can register events in advance and get notified when those events happen.
The example for async
/ await
of opening and reading files doesn't make sense to me, because in that example after .await
I have nothing to do but wait for the content to be available, so I am still blocking and not async at all.
If I use non-blocking IO like Mio or unsafe epoll
, do I still need async
/ await
? If not, in what cases should I use async
/ await
?
If I use non-blocking IO like Mio or unsafe
epoll
, do I still needasync
/await
?
No, you don't need async
/ await
: you have code that does what you want, you are happy with it, and it doesn't use async
/ await
. There's no apparent reason for you to change your code. You state this in multiple ways:
Mio works the way I understand
[Mio] is familiar to me.
I can easily use this kind of API
The same style of question could be asked about functions. Functions aren't strictly needed because we could copy-paste code everywhere it's used. The code does what someone wants, someone is happy with it, and it doesn't make use of functions. There's no apparent reason for this developer to change their code.
Yes — in general, most Rust developers will use async
/ await
when they are trying to write asynchronous code (and maybe even when they shouldn't). These keywords are mostly syntax sugar for creating a future. Futures have existed in the Rust ecosystem for a long time before the special syntax was introduced, so even the syntax isn't required. However, it does make creating futures simpler.
Futures are an abstraction of asynchronous work that are ultimately driven by an executor. One of the things that it's possible to put underneath the abstraction is an event-based IO library. The library notifies the executor that something has changed with one of the IO handles the library manages, which causes the executor to resume the future, which may realize that it's complete.
Mio is used by some of the most common futures-related crates like tokio or async-std. The Mio documentation even suggests using it with futures:
This is a low level library, if you are looking for something easier to get started with, see Tokio.
See also: