| 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 |  | 
|---|