tokio/task/
mod.rs

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(flavor = "current_thread")]
74//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
75//! let join = task::spawn(async {
76//!     // ...
77//!     "hello world!"
78//! });
79//!
80//! // ...
81//!
82//! // Await the result of the spawned task.
83//! let result = join.await?;
84//! assert_eq!(result, "hello world!");
85//! # Ok(())
86//! # }
87//! ```
88//!
89//! Again, like `std::thread`'s [`JoinHandle` type][thread_join], if the spawned
90//! task panics, awaiting its `JoinHandle` will return a [`JoinError`]. For
91//! example:
92//!
93//! ```
94//! # #[cfg(not(target_family = "wasm"))]
95//! # {
96//! use tokio::task;
97//!
98//! # #[tokio::main] async fn main() {
99//! let join = task::spawn(async {
100//!     panic!("something bad happened!")
101//! });
102//!
103//! // The returned result indicates that the task failed.
104//! assert!(join.await.is_err());
105//! # }
106//! # }
107//! ```
108//!
109//! `spawn`, `JoinHandle`, and `JoinError` are present when the "rt"
110//! feature flag is enabled.
111//!
112//! [`task::spawn`]: crate::task::spawn()
113//! [future]: std::future::Future
114//! [`std::thread::spawn`]: std::thread::spawn
115//! [`JoinHandle`]: crate::task::JoinHandle
116//! [thread_join]: std::thread::JoinHandle
117//! [`JoinError`]: crate::task::JoinError
118//!
119//! #### Cancellation
120//!
121//! Spawned tasks may be cancelled using the [`JoinHandle::abort`] or
122//! [`AbortHandle::abort`] methods. When one of these methods are called, the
123//! task is signalled to shut down next time it yields at an `.await` point. If
124//! the task is already idle, then it will be shut down as soon as possible
125//! without running again before being shut down. Additionally, shutting down a
126//! Tokio runtime (e.g. by returning from `#[tokio::main]`) immediately cancels
127//! all tasks on it.
128//!
129//! When tasks are shut down, it will stop running at whichever `.await` it has
130//! yielded at. All local variables are destroyed by running their destructor.
131//! Once shutdown has completed, awaiting the [`JoinHandle`] will fail with a
132//! [cancelled error](crate::task::JoinError::is_cancelled).
133//!
134//! Note that aborting a task does not guarantee that it fails with a cancelled
135//! error, since it may complete normally first. For example, if the task does
136//! not yield to the runtime at any point between the call to `abort` and the
137//! end of the task, then the [`JoinHandle`] will instead report that the task
138//! exited normally.
139//!
140//! Be aware that tasks spawned using [`spawn_blocking`] cannot be aborted
141//! because they are not async. If you call `abort` on a `spawn_blocking`
142//! task, then this *will not have any effect*, and the task will continue
143//! running normally. The exception is if the task has not started running
144//! yet; in that case, calling `abort` may prevent the task from starting.
145//!
146//! Be aware that calls to [`JoinHandle::abort`] just schedule the task for
147//! cancellation, and will return before the cancellation has completed. To wait
148//! for cancellation to complete, wait for the task to finish by awaiting the
149//! [`JoinHandle`]. Similarly, the [`JoinHandle::is_finished`] method does not
150//! return `true` until the cancellation has finished.
151//!
152//! Calling [`JoinHandle::abort`] multiple times has the same effect as calling
153//! it once.
154//!
155//! Tokio also provides an [`AbortHandle`], which is like the [`JoinHandle`],
156//! except that it does not provide a mechanism to wait for the task to finish.
157//! Each task can only have one [`JoinHandle`], but it can have more than one
158//! [`AbortHandle`].
159//!
160//! [`JoinHandle::abort`]: crate::task::JoinHandle::abort
161//! [`AbortHandle::abort`]: crate::task::AbortHandle::abort
162//! [`AbortHandle`]: crate::task::AbortHandle
163//! [`JoinHandle::is_finished`]: crate::task::JoinHandle::is_finished
164//!
165//! ### Blocking and Yielding
166//!
167//! As we discussed above, code running in asynchronous tasks should not perform
168//! operations that can block. A blocking operation performed in a task running
169//! on a thread that is also running other tasks would block the entire thread,
170//! preventing other tasks from running.
171//!
172//! Instead, Tokio provides two APIs for running blocking operations in an
173//! asynchronous context: [`task::spawn_blocking`] and [`task::block_in_place`].
174//!
175//! Be aware that if you call a non-async method from async code, that non-async
176//! method is still inside the asynchronous context, so you should also avoid
177//! blocking operations there. This includes destructors of objects destroyed in
178//! async code.
179//!
180//! #### `spawn_blocking`
181//!
182//! The `task::spawn_blocking` function is similar to the `task::spawn` function
183//! discussed in the previous section, but rather than spawning an
184//! _non-blocking_ future on the Tokio runtime, it instead spawns a
185//! _blocking_ function on a dedicated thread pool for blocking tasks. For
186//! example:
187//!
188//! ```
189//! use tokio::task;
190//!
191//! # async fn docs() {
192//! task::spawn_blocking(|| {
193//!     // do some compute-heavy work or call synchronous code
194//! });
195//! # }
196//! ```
197//!
198//! Just like `task::spawn`, `task::spawn_blocking` returns a `JoinHandle`
199//! which we can use to await the result of the blocking operation:
200//!
201//! ```rust
202//! # use tokio::task;
203//! # async fn docs() -> Result<(), Box<dyn std::error::Error>>{
204//! let join = task::spawn_blocking(|| {
205//!     // do some compute-heavy work or call synchronous code
206//!     "blocking completed"
207//! });
208//!
209//! let result = join.await?;
210//! assert_eq!(result, "blocking completed");
211//! # Ok(())
212//! # }
213//! ```
214//!
215//! #### `block_in_place`
216//!
217//! When using the [multi-threaded runtime][rt-multi-thread], the [`task::block_in_place`]
218//! function is also available. Like `task::spawn_blocking`, this function
219//! allows running a blocking operation from an asynchronous context. Unlike
220//! `spawn_blocking`, however, `block_in_place` works by transitioning the
221//! _current_ worker thread to a blocking thread, moving other tasks running on
222//! that thread to another worker thread. This can improve performance by avoiding
223//! context switches.
224//!
225//! For example:
226//!
227//! ```
228//! # #[cfg(not(target_family = "wasm"))]
229//! # {
230//! use tokio::task;
231//!
232//! # async fn docs() {
233//! let result = task::block_in_place(|| {
234//!     // do some compute-heavy work or call synchronous code
235//!     "blocking completed"
236//! });
237//!
238//! assert_eq!(result, "blocking completed");
239//! # }
240//! # }
241//! ```
242//!
243//! #### `yield_now`
244//!
245//! In addition, this module provides a [`task::yield_now`] async function
246//! that is analogous to the standard library's [`thread::yield_now`]. Calling
247//! and `await`ing this function will cause the current task to yield to the
248//! Tokio runtime's scheduler, allowing other tasks to be
249//! scheduled. Eventually, the yielding task will be polled again, allowing it
250//! to execute. For example:
251//!
252//! ```rust
253//! use tokio::task;
254//!
255//! # #[tokio::main(flavor = "current_thread")]
256//! # async fn main() {
257//! async {
258//!     task::spawn(async {
259//!         // ...
260//!         println!("spawned task done!")
261//!     });
262//!
263//!     // Yield, allowing the newly-spawned task to execute first.
264//!     task::yield_now().await;
265//!     println!("main task done!");
266//! }
267//! # .await;
268//! # }
269//! ```
270//!
271//! [`task::spawn_blocking`]: crate::task::spawn_blocking
272//! [`task::block_in_place`]: crate::task::block_in_place
273//! [rt-multi-thread]: ../runtime/index.html#threaded-scheduler
274//! [`task::yield_now`]: crate::task::yield_now()
275//! [`thread::yield_now`]: std::thread::yield_now
276
277cfg_rt! {
278    pub use crate::runtime::task::{JoinError, JoinHandle};
279
280    mod blocking;
281    pub use blocking::spawn_blocking;
282
283    mod spawn;
284    pub use spawn::spawn;
285
286    cfg_rt_multi_thread! {
287        pub use blocking::block_in_place;
288    }
289
290    mod yield_now;
291    pub use yield_now::yield_now;
292
293    pub mod coop;
294    #[doc(hidden)]
295    #[deprecated = "Moved to tokio::task::coop::consume_budget"]
296    pub use coop::consume_budget;
297    #[doc(hidden)]
298    #[deprecated = "Moved to tokio::task::coop::unconstrained"]
299    pub use coop::unconstrained;
300    #[doc(hidden)]
301    #[deprecated = "Moved to tokio::task::coop::Unconstrained"]
302    pub use coop::Unconstrained;
303
304    mod local;
305    pub use local::{spawn_local, LocalSet, LocalEnterGuard};
306
307    mod task_local;
308    pub use task_local::LocalKey;
309
310    #[doc(inline)]
311    pub use join_set::JoinSet;
312    pub use crate::runtime::task::AbortHandle;
313
314    // Uses #[cfg(...)] instead of macro since the macro adds docsrs annotations.
315    #[cfg(not(tokio_unstable))]
316    mod join_set;
317    #[cfg(tokio_unstable)]
318    pub mod join_set;
319
320    pub use crate::runtime::task::{Id, id, try_id};
321
322    cfg_trace! {
323        mod builder;
324        pub use builder::Builder;
325    }
326
327    /// Task-related futures.
328    pub mod futures {
329        pub use super::task_local::TaskLocalFuture;
330    }
331}
332
333cfg_not_rt! {
334    pub(crate) mod coop;
335}