blob: 551851542c94897207451c2a9cbac1a468ff9a7f [file] [log] [blame]
Stjepan Glavina1479e862019-08-12 20:18:51 +02001//! Task abstraction for building executors.
2//!
3//! # What is an executor?
4//!
5//! An async block creates a future and an async function returns one. But futures don't do
6//! anything unless they are awaited inside other async blocks or async functions. So the question
7//! arises: who or what awaits the main future that awaits others?
8//!
9//! One solution is to call [`block_on()`] on the main future, which will block
10//! the current thread and keep polling the future until it completes. But sometimes we don't want
11//! to block the current thread and would prefer to *spawn* the future to let a background thread
12//! block on it instead.
13//!
14//! This is where executors step in - they create a number of threads (typically equal to the
15//! number of CPU cores on the system) that are dedicated to polling spawned futures. Each executor
16//! thread keeps polling spawned futures in a loop and only blocks when all spawned futures are
17//! either sleeping or running.
18//!
19//! # What is a task?
20//!
21//! In order to spawn a future on an executor, one needs to allocate the future on the heap and
22//! keep some state alongside it, like whether the future is ready for polling, waiting to be woken
23//! up, or completed. This allocation is usually called a *task*.
24//!
25//! The executor then runs the spawned task by polling its future. If the future is pending on a
26//! resource, a [`Waker`] associated with the task will be registered somewhere so that the task
27//! can be woken up and run again at a later time.
28//!
29//! For example, if the future wants to read something from a TCP socket that is not ready yet, the
30//! networking system will clone the task's waker and wake it up once the socket becomes ready.
31//!
32//! # Task construction
33//!
34//! A task is constructed with [`Task::create()`]:
35//!
36//! ```
37//! # #![feature(async_await)]
38//! let future = async { 1 + 2 };
39//! let schedule = |task| unimplemented!();
40//!
41//! let (task, handle) = async_task::spawn(future, schedule, ());
42//! ```
43//!
44//! The first argument to the constructor, `()` in this example, is an arbitrary piece of data
45//! called a *tag*. This can be a task identifier, a task name, task-local storage, or something
46//! of similar nature.
47//!
48//! The second argument is the future that gets polled when the task is run.
49//!
50//! The third argument is the schedule function, which is called every time when the task gets
51//! woken up. This function should push the received task into some kind of queue of runnable
52//! tasks.
53//!
54//! The constructor returns a runnable [`Task`] and a [`JoinHandle`] that can await the result of
55//! the future.
56//!
57//! # Task scheduling
58//!
59//! TODO
60//!
61//! # Join handles
62//!
63//! TODO
64//!
65//! # Cancellation
66//!
67//! TODO
68//!
69//! # Performance
70//!
71//! TODO: explain single allocation, etc.
72//!
73//! Task [construction] incurs a single allocation only. The [`Task`] can then be run and its
74//! result awaited through the [`JoinHandle`]. When woken, the task gets automatically rescheduled.
75//! It's also possible to cancel the task so that it stops running and can't be awaited anymore.
76//!
77//! [construction]: struct.Task.html#method.create
78//! [`JoinHandle`]: struct.JoinHandle.html
79//! [`Task`]: struct.Task.html
80//! [`Future`]: https://doc.rust-lang.org/nightly/std/future/trait.Future.html
81//! [`Waker`]: https://doc.rust-lang.org/nightly/std/task/struct.Waker.html
82//! [`block_on()`]: https://docs.rs/futures-preview/*/futures/executor/fn.block_on.html
83//!
84//! # Examples
85//!
86//! A simple single-threaded executor:
87//!
88//! ```
89//! # #![feature(async_await)]
90//! use std::future::Future;
91//! use std::panic::catch_unwind;
92//! use std::thread;
93//!
94//! use async_task::{JoinHandle, Task};
95//! use crossbeam::channel::{unbounded, Sender};
96//! use futures::executor;
97//! use lazy_static::lazy_static;
98//!
99//! /// Spawns a future on the executor.
100//! fn spawn<F, R>(future: F) -> JoinHandle<R, ()>
101//! where
102//! F: Future<Output = R> + Send + 'static,
103//! R: Send + 'static,
104//! {
105//! lazy_static! {
106//! // A channel that holds scheduled tasks.
107//! static ref QUEUE: Sender<Task<()>> = {
108//! let (sender, receiver) = unbounded::<Task<()>>();
109//!
110//! // Start the executor thread.
111//! thread::spawn(|| {
112//! for task in receiver {
113//! // Ignore panics for simplicity.
114//! let _ignore_panic = catch_unwind(|| task.run());
115//! }
116//! });
117//!
118//! sender
119//! };
120//! }
121//!
122//! // Create a task that is scheduled by sending itself into the channel.
123//! let schedule = |t| QUEUE.send(t).unwrap();
124//! let (task, handle) = async_task::spawn(future, schedule, ());
125//!
126//! // Schedule the task by sending it into the channel.
127//! task.schedule();
128//!
129//! handle
130//! }
131//!
132//! // Spawn a future and await its result.
133//! let handle = spawn(async {
134//! println!("Hello, world!");
135//! });
136//! executor::block_on(handle);
137//! ```
138
139#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]
140
141mod header;
142mod join_handle;
143mod raw;
144mod state;
145mod task;
146mod utils;
147
148pub use crate::join_handle::JoinHandle;
149pub use crate::task::{spawn, Task};