1 //! Asynchronous green-threads.
2 //!
3 //! ## What are Tasks?
4 //!
5 //! A _task_ is a light weight, non-blocking unit of execution. A task is similar
6 //! to an OS thread, but rather than being managed by the OS scheduler, they are
7 //! managed by the [Tokio runtime][rt]. Another name for this general pattern is
8 //! [green threads]. If you are familiar with [Go's goroutines], [Kotlin's
9 //! coroutines], or [Erlang's processes], you can think of Tokio's tasks as
10 //! something similar.
11 //!
12 //! Key points about tasks include:
13 //!
14 //! * Tasks are **light weight**. Because tasks are scheduled by the Tokio
15 //!   runtime rather than the operating system, creating new tasks or switching
16 //!   between tasks does not require a context switch and has fairly low
17 //!   overhead. Creating, running, and destroying large numbers of tasks is
18 //!   quite cheap, especially compared to OS threads.
19 //!
20 //! * Tasks are scheduled **cooperatively**. Most operating systems implement
21 //!   _preemptive multitasking_. This is a scheduling technique where the
22 //!   operating system allows each thread to run for a period of time, and then
23 //!   _preempts_ it, temporarily pausing that thread and switching to another.
24 //!   Tasks, on the other hand, implement _cooperative multitasking_. In
25 //!   cooperative multitasking, a task is allowed to run until it _yields_,
26 //!   indicating to the Tokio runtime's scheduler that it cannot currently
27 //!   continue executing. When a task yields, the Tokio runtime switches to
28 //!   executing the next task.
29 //!
30 //! * Tasks are **non-blocking**. Typically, when an OS thread performs I/O or
31 //!   must synchronize with another thread, it _blocks_, allowing the OS to
32 //!   schedule another thread. When a task cannot continue executing, it must
33 //!   yield instead, allowing the Tokio runtime to schedule another task. Tasks
34 //!   should generally not perform system calls or other operations that could
35 //!   block a thread, as this would prevent other tasks running on the same
36 //!   thread from executing as well. Instead, this module provides APIs for
37 //!   running blocking operations in an asynchronous context.
38 //!
39 //! [rt]: crate::runtime
40 //! [green threads]: https://en.wikipedia.org/wiki/Green_threads
41 //! [Go's goroutines]: https://tour.golang.org/concurrency/1
42 //! [Kotlin's coroutines]: https://kotlinlang.org/docs/reference/coroutines-overview.html
43 //! [Erlang's processes]: http://erlang.org/doc/getting_started/conc_prog.html#processes
44 //!
45 //! ## Working with Tasks
46 //!
47 //! This module provides the following APIs for working with tasks:
48 //!
49 //! ### Spawning
50 //!
51 //! Perhaps the most important function in this module is [`task::spawn`]. This
52 //! function can be thought of as an async equivalent to the standard library's
53 //! [`thread::spawn`][`std::thread::spawn`]. It takes an `async` block or other
54 //! [future], and creates a new task to run that work concurrently:
55 //!
56 //! ```
57 //! use tokio::task;
58 //!
59 //! # async fn doc() {
60 //! task::spawn(async {
61 //!     // perform some work here...
62 //! });
63 //! # }
64 //! ```
65 //!
66 //! Like [`std::thread::spawn`], `task::spawn` returns a [`JoinHandle`] struct.
67 //! A `JoinHandle` is itself a future which may be used to await the output of
68 //! the spawned task. For example:
69 //!
70 //! ```
71 //! use tokio::task;
72 //!
73 //! # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
74 //! let join = task::spawn(async {
75 //!     // ...
76 //!     "hello world!"
77 //! });
78 //!
79 //! // ...
80 //!
81 //! // Await the result of the spawned task.
82 //! let result = join.await?;
83 //! assert_eq!(result, "hello world!");
84 //! # Ok(())
85 //! # }
86 //! ```
87 //!
88 //! Again, like `std::thread`'s [`JoinHandle` type][thread_join], if the spawned
89 //! task panics, awaiting its `JoinHandle` will return a [`JoinError`]. For
90 //! example:
91 //!
92 //! ```
93 //! use tokio::task;
94 //!
95 //! # #[tokio::main] async fn main() {
96 //! let join = task::spawn(async {
97 //!     panic!("something bad happened!")
98 //! });
99 //!
100 //! // The returned result indicates that the task failed.
101 //! assert!(join.await.is_err());
102 //! # }
103 //! ```
104 //!
105 //! `spawn`, `JoinHandle`, and `JoinError` are present when the "rt"
106 //! feature flag is enabled.
107 //!
108 //! [`task::spawn`]: crate::task::spawn()
109 //! [future]: std::future::Future
110 //! [`std::thread::spawn`]: std::thread::spawn
111 //! [`JoinHandle`]: crate::task::JoinHandle
112 //! [thread_join]: std::thread::JoinHandle
113 //! [`JoinError`]: crate::task::JoinError
114 //!
115 //! #### Cancellation
116 //!
117 //! Spawned tasks may be cancelled using the [`JoinHandle::abort`] or
118 //! [`AbortHandle::abort`] methods. When one of these methods are called, the
119 //! task is signalled to shut down next time it yields at an `.await` point. If
120 //! the task is already idle, then it will be shut down as soon as possible
121 //! without running again before being shut down. Additionally, shutting down a
122 //! Tokio runtime (e.g. by returning from `#[tokio::main]`) immediately cancels
123 //! all tasks on it.
124 //!
125 //! When tasks are shut down, it will stop running at whichever `.await` it has
126 //! yielded at. All local variables are destroyed by running their destructor.
127 //! Once shutdown has completed, awaiting the [`JoinHandle`] will fail with a
128 //! [cancelled error](crate::task::JoinError::is_cancelled).
129 //!
130 //! Note that aborting a task does not guarantee that it fails with a cancelled
131 //! error, since it may complete normally first. For example, if the task does
132 //! not yield to the runtime at any point between the call to `abort` and the
133 //! end of the task, then the [`JoinHandle`] will instead report that the task
134 //! exited normally.
135 //!
136 //! Be aware that tasks spawned using [`spawn_blocking`] cannot be aborted
137 //! because they are not async. If you call `abort` on a `spawn_blocking`
138 //! task, then this *will not have any effect*, and the task will continue
139 //! running normally. The exception is if the task has not started running
140 //! yet; in that case, calling `abort` may prevent the task from starting.
141 //!
142 //! Be aware that calls to [`JoinHandle::abort`] just schedule the task for
143 //! cancellation, and will return before the cancellation has completed. To wait
144 //! for cancellation to complete, wait for the task to finish by awaiting the
145 //! [`JoinHandle`]. Similarly, the [`JoinHandle::is_finished`] method does not
146 //! return `true` until the cancellation has finished.
147 //!
148 //! Calling [`JoinHandle::abort`] multiple times has the same effect as calling
149 //! it once.
150 //!
151 //! Tokio also provides an [`AbortHandle`], which is like the [`JoinHandle`],
152 //! except that it does not provide a mechanism to wait for the task to finish.
153 //! Each task can only have one [`JoinHandle`], but it can have more than one
154 //! [`AbortHandle`].
155 //!
156 //! [`JoinHandle::abort`]: crate::task::JoinHandle::abort
157 //! [`AbortHandle::abort`]: crate::task::AbortHandle::abort
158 //! [`AbortHandle`]: crate::task::AbortHandle
159 //! [`JoinHandle::is_finished`]: crate::task::JoinHandle::is_finished
160 //!
161 //! ### Blocking and Yielding
162 //!
163 //! As we discussed above, code running in asynchronous tasks should not perform
164 //! operations that can block. A blocking operation performed in a task running
165 //! on a thread that is also running other tasks would block the entire thread,
166 //! preventing other tasks from running.
167 //!
168 //! Instead, Tokio provides two APIs for running blocking operations in an
169 //! asynchronous context: [`task::spawn_blocking`] and [`task::block_in_place`].
170 //!
171 //! Be aware that if you call a non-async method from async code, that non-async
172 //! method is still inside the asynchronous context, so you should also avoid
173 //! blocking operations there. This includes destructors of objects destroyed in
174 //! async code.
175 //!
176 //! #### `spawn_blocking`
177 //!
178 //! The `task::spawn_blocking` function is similar to the `task::spawn` function
179 //! discussed in the previous section, but rather than spawning an
180 //! _non-blocking_ future on the Tokio runtime, it instead spawns a
181 //! _blocking_ function on a dedicated thread pool for blocking tasks. For
182 //! example:
183 //!
184 //! ```
185 //! use tokio::task;
186 //!
187 //! # async fn docs() {
188 //! task::spawn_blocking(|| {
189 //!     // do some compute-heavy work or call synchronous code
190 //! });
191 //! # }
192 //! ```
193 //!
194 //! Just like `task::spawn`, `task::spawn_blocking` returns a `JoinHandle`
195 //! which we can use to await the result of the blocking operation:
196 //!
197 //! ```rust
198 //! # use tokio::task;
199 //! # async fn docs() -> Result<(), Box<dyn std::error::Error>>{
200 //! let join = task::spawn_blocking(|| {
201 //!     // do some compute-heavy work or call synchronous code
202 //!     "blocking completed"
203 //! });
204 //!
205 //! let result = join.await?;
206 //! assert_eq!(result, "blocking completed");
207 //! # Ok(())
208 //! # }
209 //! ```
210 //!
211 //! #### `block_in_place`
212 //!
213 //! When using the [multi-threaded runtime][rt-multi-thread], the [`task::block_in_place`]
214 //! function is also available. Like `task::spawn_blocking`, this function
215 //! allows running a blocking operation from an asynchronous context. Unlike
216 //! `spawn_blocking`, however, `block_in_place` works by transitioning the
217 //! _current_ worker thread to a blocking thread, moving other tasks running on
218 //! that thread to another worker thread. This can improve performance by avoiding
219 //! context switches.
220 //!
221 //! For example:
222 //!
223 //! ```
224 //! use tokio::task;
225 //!
226 //! # async fn docs() {
227 //! let result = task::block_in_place(|| {
228 //!     // do some compute-heavy work or call synchronous code
229 //!     "blocking completed"
230 //! });
231 //!
232 //! assert_eq!(result, "blocking completed");
233 //! # }
234 //! ```
235 //!
236 //! #### `yield_now`
237 //!
238 //! In addition, this module provides a [`task::yield_now`] async function
239 //! that is analogous to the standard library's [`thread::yield_now`]. Calling
240 //! and `await`ing this function will cause the current task to yield to the
241 //! Tokio runtime's scheduler, allowing other tasks to be
242 //! scheduled. Eventually, the yielding task will be polled again, allowing it
243 //! to execute. For example:
244 //!
245 //! ```rust
246 //! use tokio::task;
247 //!
248 //! # #[tokio::main] async fn main() {
249 //! async {
250 //!     task::spawn(async {
251 //!         // ...
252 //!         println!("spawned task done!")
253 //!     });
254 //!
255 //!     // Yield, allowing the newly-spawned task to execute first.
256 //!     task::yield_now().await;
257 //!     println!("main task done!");
258 //! }
259 //! # .await;
260 //! # }
261 //! ```
262 //!
263 //! ### Cooperative scheduling
264 //!
265 //! A single call to [`poll`] on a top-level task may potentially do a lot of
266 //! work before it returns `Poll::Pending`. If a task runs for a long period of
267 //! time without yielding back to the executor, it can starve other tasks
268 //! waiting on that executor to execute them, or drive underlying resources.
269 //! Since Rust does not have a runtime, it is difficult to forcibly preempt a
270 //! long-running task. Instead, this module provides an opt-in mechanism for
271 //! futures to collaborate with the executor to avoid starvation.
272 //!
273 //! Consider a future like this one:
274 //!
275 //! ```
276 //! # use tokio_stream::{Stream, StreamExt};
277 //! async fn drop_all<I: Stream + Unpin>(mut input: I) {
278 //!     while let Some(_) = input.next().await {}
279 //! }
280 //! ```
281 //!
282 //! It may look harmless, but consider what happens under heavy load if the
283 //! input stream is _always_ ready. If we spawn `drop_all`, the task will never
284 //! yield, and will starve other tasks and resources on the same executor.
285 //!
286 //! To account for this, Tokio has explicit yield points in a number of library
287 //! functions, which force tasks to return to the executor periodically.
288 //!
289 //!
290 //! #### unconstrained
291 //!
292 //! If necessary, [`task::unconstrained`] lets you opt a future out of Tokio's cooperative
293 //! scheduling. When a future is wrapped with `unconstrained`, it will never be forced to yield to
294 //! Tokio. For example:
295 //!
296 //! ```
297 //! # #[tokio::main]
298 //! # async fn main() {
299 //! use tokio::{task, sync::mpsc};
300 //!
301 //! let fut = async {
302 //!     let (tx, mut rx) = mpsc::unbounded_channel();
303 //!
304 //!     for i in 0..1000 {
305 //!         let _ = tx.send(());
306 //!         // This will always be ready. If coop was in effect, this code would be forced to yield
307 //!         // periodically. However, if left unconstrained, then this code will never yield.
308 //!         rx.recv().await;
309 //!     }
310 //! };
311 //!
312 //! task::unconstrained(fut).await;
313 //! # }
314 //! ```
315 //!
316 //! [`task::spawn_blocking`]: crate::task::spawn_blocking
317 //! [`task::block_in_place`]: crate::task::block_in_place
318 //! [rt-multi-thread]: ../runtime/index.html#threaded-scheduler
319 //! [`task::yield_now`]: crate::task::yield_now()
320 //! [`thread::yield_now`]: std::thread::yield_now
321 //! [`task::unconstrained`]: crate::task::unconstrained()
322 //! [`poll`]: method@std::future::Future::poll
323 
324 cfg_rt! {
325     pub use crate::runtime::task::{JoinError, JoinHandle};
326 
327     mod blocking;
328     pub use blocking::spawn_blocking;
329 
330     mod spawn;
331     pub use spawn::spawn;
332 
333     cfg_rt_multi_thread! {
334         pub use blocking::block_in_place;
335     }
336 
337     mod yield_now;
338     pub use yield_now::yield_now;
339 
340     mod consume_budget;
341     pub use consume_budget::consume_budget;
342 
343     mod local;
344     pub use local::{spawn_local, LocalSet, LocalEnterGuard};
345 
346     mod task_local;
347     pub use task_local::LocalKey;
348 
349     mod unconstrained;
350     pub use unconstrained::{unconstrained, Unconstrained};
351 
352     #[doc(inline)]
353     pub use join_set::JoinSet;
354     pub use crate::runtime::task::AbortHandle;
355 
356     // Uses #[cfg(...)] instead of macro since the macro adds docsrs annotations.
357     #[cfg(not(tokio_unstable))]
358     mod join_set;
359     #[cfg(tokio_unstable)]
360     pub mod join_set;
361 
362     pub use crate::runtime::task::{Id, id, try_id};
363 
364     cfg_trace! {
365         mod builder;
366         pub use builder::Builder;
367     }
368 
369     /// Task-related futures.
370     pub mod futures {
371         pub use super::task_local::TaskLocalFuture;
372     }
373 }
374