This is a tutorial dedicated to helping you learn asynchronous programming via Futures library through simple step by step examples.
What is Futures?
It is a Rust library that allows you achieve a Zero-cost asynchronous programming in Rust.
futures-rs
is a library providing the foundations for asynchronous programming in Rust. It includes key trait definitions like Stream
, as well as utilities like join!
, select!
, and various futures combinator methods which enable expressive asynchronous control flow.
Installation
To install it declare it in the Cargo.toml
:
[dependencies]
futures = "0.3"
Use
Then use it. Start by importing:
use futures::future::Future;
Let's look at some examples.
Example 1: Rust Futures Example
A simple rust futures-rs example.
Step 1: Install it
Install it as has been described.
Step 2: Write Code
Here's an imperative example:
use futures::channel::mpsc;
use futures::executor; //standard executors to provide a context for futures and streams
use futures::executor::ThreadPool;
use futures::StreamExt;
fn main() {
let pool = ThreadPool::new().expect("Failed to build pool");
let (tx, mut rx) = mpsc::unbounded::<i32>();
// Create a future by an async block, where async is responsible for generating
// an implementation of Future. At this point no executor has been provided
// to this future, so it will not be running.
let fut_values = async {
// Create another async block, again where Future is implemented by
// async. Since this is inside of a parent async block, it will be
// provided with the executor of the parent block when the parent
// block is executed.
//
// This executor chaining is done by Future::poll whose second argument
// is a std::task::Context. This represents our executor, and the Future
// implemented by this async block can be polled using the parent async
// block's executor.
let fut_tx_result = async move {
(0..100).for_each(|v| {
tx.unbounded_send(v).expect("Failed to send");
})
};
// Use the provided thread pool to spawn the transmission
pool.spawn_ok(fut_tx_result);
let mut pending = vec![];
// Use the provided executor to wait for the next value
// of the stream to be available.
while let Some(v) = rx.next().await {
pending.push(v * 2);
}
pending
};
// Actually execute the above future, which will invoke Future::poll and
// subsequently chain appropriate Future::poll and methods needing executors
// to drive all futures. Eventually fut_values will be driven to completion.
let values: Vec<i32> = executor::block_on(fut_values);
println!("Values={:?}", values);
}
Reference
Read more here.