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 //! ### Blocking and Yielding 116 //! 117 //! As we discussed above, code running in asynchronous tasks should not perform 118 //! operations that can block. A blocking operation performed in a task running 119 //! on a thread that is also running other tasks would block the entire thread, 120 //! preventing other tasks from running. 121 //! 122 //! Instead, Tokio provides two APIs for running blocking operations in an 123 //! asynchronous context: [`task::spawn_blocking`] and [`task::block_in_place`]. 124 //! 125 //! Be aware that if you call a non-async method from async code, that non-async 126 //! method is still inside the asynchronous context, so you should also avoid 127 //! blocking operations there. This includes destructors of objects destroyed in 128 //! async code. 129 //! 130 //! #### spawn_blocking 131 //! 132 //! The `task::spawn_blocking` function is similar to the `task::spawn` function 133 //! discussed in the previous section, but rather than spawning an 134 //! _non-blocking_ future on the Tokio runtime, it instead spawns a 135 //! _blocking_ function on a dedicated thread pool for blocking tasks. For 136 //! example: 137 //! 138 //! ``` 139 //! use tokio::task; 140 //! 141 //! # async fn docs() { 142 //! task::spawn_blocking(|| { 143 //! // do some compute-heavy work or call synchronous code 144 //! }); 145 //! # } 146 //! ``` 147 //! 148 //! Just like `task::spawn`, `task::spawn_blocking` returns a `JoinHandle` 149 //! which we can use to await the result of the blocking operation: 150 //! 151 //! ```rust 152 //! # use tokio::task; 153 //! # async fn docs() -> Result<(), Box<dyn std::error::Error>>{ 154 //! let join = task::spawn_blocking(|| { 155 //! // do some compute-heavy work or call synchronous code 156 //! "blocking completed" 157 //! }); 158 //! 159 //! let result = join.await?; 160 //! assert_eq!(result, "blocking completed"); 161 //! # Ok(()) 162 //! # } 163 //! ``` 164 //! 165 //! #### block_in_place 166 //! 167 //! When using the [multi-threaded runtime][rt-multi-thread], the [`task::block_in_place`] 168 //! function is also available. Like `task::spawn_blocking`, this function 169 //! allows running a blocking operation from an asynchronous context. Unlike 170 //! `spawn_blocking`, however, `block_in_place` works by transitioning the 171 //! _current_ worker thread to a blocking thread, moving other tasks running on 172 //! that thread to another worker thread. This can improve performance by avoiding 173 //! context switches. 174 //! 175 //! For example: 176 //! 177 //! ``` 178 //! use tokio::task; 179 //! 180 //! # async fn docs() { 181 //! let result = task::block_in_place(|| { 182 //! // do some compute-heavy work or call synchronous code 183 //! "blocking completed" 184 //! }); 185 //! 186 //! assert_eq!(result, "blocking completed"); 187 //! # } 188 //! ``` 189 //! 190 //! #### yield_now 191 //! 192 //! In addition, this module provides a [`task::yield_now`] async function 193 //! that is analogous to the standard library's [`thread::yield_now`]. Calling 194 //! and `await`ing this function will cause the current task to yield to the 195 //! Tokio runtime's scheduler, allowing other tasks to be 196 //! scheduled. Eventually, the yielding task will be polled again, allowing it 197 //! to execute. For example: 198 //! 199 //! ```rust 200 //! use tokio::task; 201 //! 202 //! # #[tokio::main] async fn main() { 203 //! async { 204 //! task::spawn(async { 205 //! // ... 206 //! println!("spawned task done!") 207 //! }); 208 //! 209 //! // Yield, allowing the newly-spawned task to execute first. 210 //! task::yield_now().await; 211 //! println!("main task done!"); 212 //! } 213 //! # .await; 214 //! # } 215 //! ``` 216 //! 217 //! ### Cooperative scheduling 218 //! 219 //! A single call to [`poll`] on a top-level task may potentially do a lot of 220 //! work before it returns `Poll::Pending`. If a task runs for a long period of 221 //! time without yielding back to the executor, it can starve other tasks 222 //! waiting on that executor to execute them, or drive underlying resources. 223 //! Since Rust does not have a runtime, it is difficult to forcibly preempt a 224 //! long-running task. Instead, this module provides an opt-in mechanism for 225 //! futures to collaborate with the executor to avoid starvation. 226 //! 227 //! Consider a future like this one: 228 //! 229 //! ``` 230 //! # use tokio_stream::{Stream, StreamExt}; 231 //! async fn drop_all<I: Stream + Unpin>(mut input: I) { 232 //! while let Some(_) = input.next().await {} 233 //! } 234 //! ``` 235 //! 236 //! It may look harmless, but consider what happens under heavy load if the 237 //! input stream is _always_ ready. If we spawn `drop_all`, the task will never 238 //! yield, and will starve other tasks and resources on the same executor. 239 //! 240 //! To account for this, Tokio has explicit yield points in a number of library 241 //! functions, which force tasks to return to the executor periodically. 242 //! 243 //! 244 //! #### unconstrained 245 //! 246 //! If necessary, [`task::unconstrained`] lets you opt a future out of of Tokio's cooperative 247 //! scheduling. When a future is wrapped with `unconstrained`, it will never be forced to yield to 248 //! Tokio. For example: 249 //! 250 //! ``` 251 //! # #[tokio::main] 252 //! # async fn main() { 253 //! use tokio::{task, sync::mpsc}; 254 //! 255 //! let fut = async { 256 //! let (tx, mut rx) = mpsc::unbounded_channel(); 257 //! 258 //! for i in 0..1000 { 259 //! let _ = tx.send(()); 260 //! // This will always be ready. If coop was in effect, this code would be forced to yield 261 //! // periodically. However, if left unconstrained, then this code will never yield. 262 //! rx.recv().await; 263 //! } 264 //! }; 265 //! 266 //! task::unconstrained(fut).await; 267 //! # } 268 //! ``` 269 //! 270 //! [`task::spawn_blocking`]: crate::task::spawn_blocking 271 //! [`task::block_in_place`]: crate::task::block_in_place 272 //! [rt-multi-thread]: ../runtime/index.html#threaded-scheduler 273 //! [`task::yield_now`]: crate::task::yield_now() 274 //! [`thread::yield_now`]: std::thread::yield_now 275 //! [`task::unconstrained`]: crate::task::unconstrained() 276 //! [`poll`]: method@std::future::Future::poll 277 278 cfg_rt! { 279 pub use crate::runtime::task::{JoinError, JoinHandle}; 280 281 cfg_not_wasi! { 282 mod blocking; 283 pub use blocking::spawn_blocking; 284 } 285 286 mod spawn; 287 pub use spawn::spawn; 288 289 cfg_rt_multi_thread! { 290 pub use blocking::block_in_place; 291 } 292 293 mod yield_now; 294 pub use yield_now::yield_now; 295 296 cfg_unstable! { 297 mod consume_budget; 298 pub use consume_budget::consume_budget; 299 } 300 301 mod local; 302 pub use local::{spawn_local, LocalSet, LocalEnterGuard}; 303 304 mod task_local; 305 pub use task_local::LocalKey; 306 307 mod unconstrained; 308 pub use unconstrained::{unconstrained, Unconstrained}; 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 cfg_unstable! { 321 pub use crate::runtime::task::{Id, id, try_id}; 322 } 323 324 cfg_trace! { 325 mod builder; 326 pub use builder::Builder; 327 } 328 329 /// Task-related futures. 330 pub mod futures { 331 pub use super::task_local::TaskLocalFuture; 332 } 333 } 334