lib.rs |
Abstractions for asynchronous programming.
This crate provides a number of core abstractions for writing asynchronous
code:
- [Futures](crate::future) are single eventual values produced by
asynchronous computations. Some programming languages (e.g. JavaScript)
call this concept "promise".
- [Streams](crate::stream) represent a series of values
produced asynchronously.
- [Sinks](crate::sink) provide support for asynchronous writing of
data.
- [Executors](crate::executor) are responsible for running asynchronous
tasks.
The crate also contains abstractions for [asynchronous I/O](crate::io) and
[cross-task communication](crate::channel).
Underlying all of this is the *task system*, which is a form of lightweight
threading. Large asynchronous computations are built up using futures,
streams and sinks, and then spawned as independent tasks that are run to
completion, but *do not block* the thread running them.
The following example describes how the task system context is built and used
within macros and keywords such as async and await!.
```rust
# 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, rx) = mpsc::unbounded::<i32>();
// Create a future by an async block, where async is responsible for 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 the Future implementation
// is generated 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 generated future
// responsible for transmission
pool.spawn_ok(fut_tx_result);
let fut_values = rx
.map(|v| v * 2)
.collect();
// Use the executor provided to this async block to wait for the
// future to complete.
fut_values.await
};
// 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);
# }
# std::thread::sleep(std::time::Duration::from_millis(500)); // wait for background threads closed: https://github.com/rust-lang/miri/issues/1371
}
```
The majority of examples and code snippets in this crate assume that they are
inside an async block as written above. |
9772 |