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