1 | //! The Tokio runtime. |
2 | //! |
3 | //! Unlike other Rust programs, asynchronous applications require runtime |
4 | //! support. In particular, the following runtime services are necessary: |
5 | //! |
6 | //! * An **I/O event loop**, called the driver, which drives I/O resources and |
7 | //! dispatches I/O events to tasks that depend on them. |
8 | //! * A **scheduler** to execute [tasks] that use these I/O resources. |
9 | //! * A **timer** for scheduling work to run after a set period of time. |
10 | //! |
11 | //! Tokio's [`Runtime`] bundles all of these services as a single type, allowing |
12 | //! them to be started, shut down, and configured together. However, often it is |
13 | //! not required to configure a [`Runtime`] manually, and a user may just use the |
14 | //! [`tokio::main`] attribute macro, which creates a [`Runtime`] under the hood. |
15 | //! |
16 | //! # Usage |
17 | //! |
18 | //! When no fine tuning is required, the [`tokio::main`] attribute macro can be |
19 | //! used. |
20 | //! |
21 | //! ```no_run |
22 | //! use tokio::net::TcpListener; |
23 | //! use tokio::io::{AsyncReadExt, AsyncWriteExt}; |
24 | //! |
25 | //! #[tokio::main] |
26 | //! async fn main() -> Result<(), Box<dyn std::error::Error>> { |
27 | //! let listener = TcpListener::bind("127.0.0.1:8080" ).await?; |
28 | //! |
29 | //! loop { |
30 | //! let (mut socket, _) = listener.accept().await?; |
31 | //! |
32 | //! tokio::spawn(async move { |
33 | //! let mut buf = [0; 1024]; |
34 | //! |
35 | //! // In a loop, read data from the socket and write the data back. |
36 | //! loop { |
37 | //! let n = match socket.read(&mut buf).await { |
38 | //! // socket closed |
39 | //! Ok(n) if n == 0 => return, |
40 | //! Ok(n) => n, |
41 | //! Err(e) => { |
42 | //! println!("failed to read from socket; err = {:?}" , e); |
43 | //! return; |
44 | //! } |
45 | //! }; |
46 | //! |
47 | //! // Write the data back |
48 | //! if let Err(e) = socket.write_all(&buf[0..n]).await { |
49 | //! println!("failed to write to socket; err = {:?}" , e); |
50 | //! return; |
51 | //! } |
52 | //! } |
53 | //! }); |
54 | //! } |
55 | //! } |
56 | //! ``` |
57 | //! |
58 | //! From within the context of the runtime, additional tasks are spawned using |
59 | //! the [`tokio::spawn`] function. Futures spawned using this function will be |
60 | //! executed on the same thread pool used by the [`Runtime`]. |
61 | //! |
62 | //! A [`Runtime`] instance can also be used directly. |
63 | //! |
64 | //! ```no_run |
65 | //! use tokio::net::TcpListener; |
66 | //! use tokio::io::{AsyncReadExt, AsyncWriteExt}; |
67 | //! use tokio::runtime::Runtime; |
68 | //! |
69 | //! fn main() -> Result<(), Box<dyn std::error::Error>> { |
70 | //! // Create the runtime |
71 | //! let rt = Runtime::new()?; |
72 | //! |
73 | //! // Spawn the root task |
74 | //! rt.block_on(async { |
75 | //! let listener = TcpListener::bind("127.0.0.1:8080" ).await?; |
76 | //! |
77 | //! loop { |
78 | //! let (mut socket, _) = listener.accept().await?; |
79 | //! |
80 | //! tokio::spawn(async move { |
81 | //! let mut buf = [0; 1024]; |
82 | //! |
83 | //! // In a loop, read data from the socket and write the data back. |
84 | //! loop { |
85 | //! let n = match socket.read(&mut buf).await { |
86 | //! // socket closed |
87 | //! Ok(n) if n == 0 => return, |
88 | //! Ok(n) => n, |
89 | //! Err(e) => { |
90 | //! println!("failed to read from socket; err = {:?}" , e); |
91 | //! return; |
92 | //! } |
93 | //! }; |
94 | //! |
95 | //! // Write the data back |
96 | //! if let Err(e) = socket.write_all(&buf[0..n]).await { |
97 | //! println!("failed to write to socket; err = {:?}" , e); |
98 | //! return; |
99 | //! } |
100 | //! } |
101 | //! }); |
102 | //! } |
103 | //! }) |
104 | //! } |
105 | //! ``` |
106 | //! |
107 | //! ## Runtime Configurations |
108 | //! |
109 | //! Tokio provides multiple task scheduling strategies, suitable for different |
110 | //! applications. The [runtime builder] or `#[tokio::main]` attribute may be |
111 | //! used to select which scheduler to use. |
112 | //! |
113 | //! #### Multi-Thread Scheduler |
114 | //! |
115 | //! The multi-thread scheduler executes futures on a _thread pool_, using a |
116 | //! work-stealing strategy. By default, it will start a worker thread for each |
117 | //! CPU core available on the system. This tends to be the ideal configuration |
118 | //! for most applications. The multi-thread scheduler requires the `rt-multi-thread` |
119 | //! feature flag, and is selected by default: |
120 | //! ``` |
121 | //! use tokio::runtime; |
122 | //! |
123 | //! # fn main() -> Result<(), Box<dyn std::error::Error>> { |
124 | //! let threaded_rt = runtime::Runtime::new()?; |
125 | //! # Ok(()) } |
126 | //! ``` |
127 | //! |
128 | //! Most applications should use the multi-thread scheduler, except in some |
129 | //! niche use-cases, such as when running only a single thread is required. |
130 | //! |
131 | //! #### Current-Thread Scheduler |
132 | //! |
133 | //! The current-thread scheduler provides a _single-threaded_ future executor. |
134 | //! All tasks will be created and executed on the current thread. This requires |
135 | //! the `rt` feature flag. |
136 | //! ``` |
137 | //! use tokio::runtime; |
138 | //! |
139 | //! # fn main() -> Result<(), Box<dyn std::error::Error>> { |
140 | //! let rt = runtime::Builder::new_current_thread() |
141 | //! .build()?; |
142 | //! # Ok(()) } |
143 | //! ``` |
144 | //! |
145 | //! #### Resource drivers |
146 | //! |
147 | //! When configuring a runtime by hand, no resource drivers are enabled by |
148 | //! default. In this case, attempting to use networking types or time types will |
149 | //! fail. In order to enable these types, the resource drivers must be enabled. |
150 | //! This is done with [`Builder::enable_io`] and [`Builder::enable_time`]. As a |
151 | //! shorthand, [`Builder::enable_all`] enables both resource drivers. |
152 | //! |
153 | //! ## Lifetime of spawned threads |
154 | //! |
155 | //! The runtime may spawn threads depending on its configuration and usage. The |
156 | //! multi-thread scheduler spawns threads to schedule tasks and for `spawn_blocking` |
157 | //! calls. |
158 | //! |
159 | //! While the `Runtime` is active, threads may shut down after periods of being |
160 | //! idle. Once `Runtime` is dropped, all runtime threads have usually been |
161 | //! terminated, but in the presence of unstoppable spawned work are not |
162 | //! guaranteed to have been terminated. See the |
163 | //! [struct level documentation](Runtime#shutdown) for more details. |
164 | //! |
165 | //! [tasks]: crate::task |
166 | //! [`Runtime`]: Runtime |
167 | //! [`tokio::spawn`]: crate::spawn |
168 | //! [`tokio::main`]: ../attr.main.html |
169 | //! [runtime builder]: crate::runtime::Builder |
170 | //! [`Runtime::new`]: crate::runtime::Runtime::new |
171 | //! [`Builder::threaded_scheduler`]: crate::runtime::Builder::threaded_scheduler |
172 | //! [`Builder::enable_io`]: crate::runtime::Builder::enable_io |
173 | //! [`Builder::enable_time`]: crate::runtime::Builder::enable_time |
174 | //! [`Builder::enable_all`]: crate::runtime::Builder::enable_all |
175 | //! |
176 | //! # Detailed runtime behavior |
177 | //! |
178 | //! This section gives more details into how the Tokio runtime will schedule |
179 | //! tasks for execution. |
180 | //! |
181 | //! At its most basic level, a runtime has a collection of tasks that need to be |
182 | //! scheduled. It will repeatedly remove a task from that collection and |
183 | //! schedule it (by calling [`poll`]). When the collection is empty, the thread |
184 | //! will go to sleep until a task is added to the collection. |
185 | //! |
186 | //! However, the above is not sufficient to guarantee a well-behaved runtime. |
187 | //! For example, the runtime might have a single task that is always ready to be |
188 | //! scheduled, and schedule that task every time. This is a problem because it |
189 | //! starves other tasks by not scheduling them. To solve this, Tokio provides |
190 | //! the following fairness guarantee: |
191 | //! |
192 | //! > If the total number of tasks does not grow without bound, and no task is |
193 | //! > [blocking the thread], then it is guaranteed that tasks are scheduled |
194 | //! > fairly. |
195 | //! |
196 | //! Or, more formally: |
197 | //! |
198 | //! > Under the following two assumptions: |
199 | //! > |
200 | //! > * There is some number `MAX_TASKS` such that the total number of tasks on |
201 | //! > the runtime at any specific point in time never exceeds `MAX_TASKS`. |
202 | //! > * There is some number `MAX_SCHEDULE` such that calling [`poll`] on any |
203 | //! > task spawned on the runtime returns within `MAX_SCHEDULE` time units. |
204 | //! > |
205 | //! > Then, there is some number `MAX_DELAY` such that when a task is woken, it |
206 | //! > will be scheduled by the runtime within `MAX_DELAY` time units. |
207 | //! |
208 | //! (Here, `MAX_TASKS` and `MAX_SCHEDULE` can be any number and the user of |
209 | //! the runtime may choose them. The `MAX_DELAY` number is controlled by the |
210 | //! runtime, and depends on the value of `MAX_TASKS` and `MAX_SCHEDULE`.) |
211 | //! |
212 | //! Other than the above fairness guarantee, there is no guarantee about the |
213 | //! order in which tasks are scheduled. There is also no guarantee that the |
214 | //! runtime is equally fair to all tasks. For example, if the runtime has two |
215 | //! tasks A and B that are both ready, then the runtime may schedule A five |
216 | //! times before it schedules B. This is the case even if A yields using |
217 | //! [`yield_now`]. All that is guaranteed is that it will schedule B eventually. |
218 | //! |
219 | //! Normally, tasks are scheduled only if they have been woken by calling |
220 | //! [`wake`] on their waker. However, this is not guaranteed, and Tokio may |
221 | //! schedule tasks that have not been woken under some circumstances. This is |
222 | //! called a spurious wakeup. |
223 | //! |
224 | //! ## IO and timers |
225 | //! |
226 | //! Beyond just scheduling tasks, the runtime must also manage IO resources and |
227 | //! timers. It does this by periodically checking whether there are any IO |
228 | //! resources or timers that are ready, and waking the relevant task so that |
229 | //! it will be scheduled. |
230 | //! |
231 | //! These checks are performed periodically between scheduling tasks. Under the |
232 | //! same assumptions as the previous fairness guarantee, Tokio guarantees that |
233 | //! it will wake tasks with an IO or timer event within some maximum number of |
234 | //! time units. |
235 | //! |
236 | //! ## Current thread runtime (behavior at the time of writing) |
237 | //! |
238 | //! This section describes how the [current thread runtime] behaves today. This |
239 | //! behavior may change in future versions of Tokio. |
240 | //! |
241 | //! The current thread runtime maintains two FIFO queues of tasks that are ready |
242 | //! to be scheduled: the global queue and the local queue. The runtime will prefer |
243 | //! to choose the next task to schedule from the local queue, and will only pick a |
244 | //! task from the global queue if the local queue is empty, or if it has picked |
245 | //! a task from the local queue 31 times in a row. The number 31 can be |
246 | //! changed using the [`global_queue_interval`] setting. |
247 | //! |
248 | //! The runtime will check for new IO or timer events whenever there are no |
249 | //! tasks ready to be scheduled, or when it has scheduled 61 tasks in a row. The |
250 | //! number 61 may be changed using the [`event_interval`] setting. |
251 | //! |
252 | //! When a task is woken from within a task running on the runtime, then the |
253 | //! woken task is added directly to the local queue. Otherwise, the task is |
254 | //! added to the global queue. The current thread runtime does not use [the lifo |
255 | //! slot optimization]. |
256 | //! |
257 | //! ## Multi threaded runtime (behavior at the time of writing) |
258 | //! |
259 | //! This section describes how the [multi thread runtime] behaves today. This |
260 | //! behavior may change in future versions of Tokio. |
261 | //! |
262 | //! A multi thread runtime has a fixed number of worker threads, which are all |
263 | //! created on startup. The multi thread runtime maintains one global queue, and |
264 | //! a local queue for each worker thread. The local queue of a worker thread can |
265 | //! fit at most 256 tasks. If more than 256 tasks are added to the local queue, |
266 | //! then half of them are moved to the global queue to make space. |
267 | //! |
268 | //! The runtime will prefer to choose the next task to schedule from the local |
269 | //! queue, and will only pick a task from the global queue if the local queue is |
270 | //! empty, or if it has picked a task from the local queue |
271 | //! [`global_queue_interval`] times in a row. If the value of |
272 | //! [`global_queue_interval`] is not explicitly set using the runtime builder, |
273 | //! then the runtime will dynamically compute it using a heuristic that targets |
274 | //! 10ms intervals between each check of the global queue (based on the |
275 | //! [`worker_mean_poll_time`] metric). |
276 | //! |
277 | //! If both the local queue and global queue is empty, then the worker thread |
278 | //! will attempt to steal tasks from the local queue of another worker thread. |
279 | //! Stealing is done by moving half of the tasks in one local queue to another |
280 | //! local queue. |
281 | //! |
282 | //! The runtime will check for new IO or timer events whenever there are no |
283 | //! tasks ready to be scheduled, or when it has scheduled 61 tasks in a row. The |
284 | //! number 61 may be changed using the [`event_interval`] setting. |
285 | //! |
286 | //! The multi thread runtime uses [the lifo slot optimization]: Whenever a task |
287 | //! wakes up another task, the other task is added to the worker thread's lifo |
288 | //! slot instead of being added to a queue. If there was already a task in the |
289 | //! lifo slot when this happened, then the lifo slot is replaced, and the task |
290 | //! that used to be in the lifo slot is placed in the thread's local queue. |
291 | //! When the runtime finishes scheduling a task, it will schedule the task in |
292 | //! the lifo slot immediately, if any. When the lifo slot is used, the [coop |
293 | //! budget] is not reset. Furthermore, if a worker thread uses the lifo slot |
294 | //! three times in a row, it is temporarily disabled until the worker thread has |
295 | //! scheduled a task that didn't come from the lifo slot. The lifo slot can be |
296 | //! disabled using the [`disable_lifo_slot`] setting. The lifo slot is separate |
297 | //! from the local queue, so other worker threads cannot steal the task in the |
298 | //! lifo slot. |
299 | //! |
300 | //! When a task is woken from a thread that is not a worker thread, then the |
301 | //! task is placed in the global queue. |
302 | //! |
303 | //! [`poll`]: std::future::Future::poll |
304 | //! [`wake`]: std::task::Waker::wake |
305 | //! [`yield_now`]: crate::task::yield_now |
306 | //! [blocking the thread]: https://ryhl.io/blog/async-what-is-blocking/ |
307 | //! [current thread runtime]: crate::runtime::Builder::new_current_thread |
308 | //! [multi thread runtime]: crate::runtime::Builder::new_multi_thread |
309 | //! [`global_queue_interval`]: crate::runtime::Builder::global_queue_interval |
310 | //! [`event_interval`]: crate::runtime::Builder::event_interval |
311 | //! [`disable_lifo_slot`]: crate::runtime::Builder::disable_lifo_slot |
312 | //! [the lifo slot optimization]: crate::runtime::Builder::disable_lifo_slot |
313 | //! [coop budget]: crate::task#cooperative-scheduling |
314 | //! [`worker_mean_poll_time`]: crate::runtime::RuntimeMetrics::worker_mean_poll_time |
315 | |
316 | // At the top due to macros |
317 | #[cfg (test)] |
318 | #[cfg (not(target_family = "wasm" ))] |
319 | #[macro_use ] |
320 | mod tests; |
321 | |
322 | pub(crate) mod context; |
323 | |
324 | pub(crate) mod coop; |
325 | |
326 | pub(crate) mod park; |
327 | |
328 | mod driver; |
329 | |
330 | pub(crate) mod scheduler; |
331 | |
332 | cfg_io_driver_impl! { |
333 | pub(crate) mod io; |
334 | } |
335 | |
336 | cfg_process_driver! { |
337 | mod process; |
338 | } |
339 | |
340 | cfg_time! { |
341 | pub(crate) mod time; |
342 | } |
343 | |
344 | cfg_signal_internal_and_unix! { |
345 | pub(crate) mod signal; |
346 | } |
347 | |
348 | cfg_rt! { |
349 | pub(crate) mod task; |
350 | |
351 | mod config; |
352 | use config::Config; |
353 | |
354 | mod blocking; |
355 | #[cfg_attr (target_os = "wasi" , allow(unused_imports))] |
356 | pub(crate) use blocking::spawn_blocking; |
357 | |
358 | cfg_trace! { |
359 | pub(crate) use blocking::Mandatory; |
360 | } |
361 | |
362 | cfg_fs! { |
363 | pub(crate) use blocking::spawn_mandatory_blocking; |
364 | } |
365 | |
366 | mod builder; |
367 | pub use self::builder::Builder; |
368 | cfg_unstable! { |
369 | mod id; |
370 | #[cfg_attr (not(tokio_unstable), allow(unreachable_pub))] |
371 | pub use id::Id; |
372 | |
373 | pub use self::builder::UnhandledPanic; |
374 | pub use crate::util::rand::RngSeed; |
375 | } |
376 | |
377 | cfg_taskdump! { |
378 | pub mod dump; |
379 | pub use dump::Dump; |
380 | } |
381 | |
382 | mod handle; |
383 | pub use handle::{EnterGuard, Handle, TryCurrentError}; |
384 | |
385 | mod runtime; |
386 | pub use runtime::{Runtime, RuntimeFlavor}; |
387 | |
388 | mod thread_id; |
389 | pub(crate) use thread_id::ThreadId; |
390 | |
391 | cfg_metrics! { |
392 | mod metrics; |
393 | pub use metrics::{RuntimeMetrics, HistogramScale}; |
394 | |
395 | pub(crate) use metrics::{MetricsBatch, SchedulerMetrics, WorkerMetrics, HistogramBuilder}; |
396 | |
397 | cfg_net! { |
398 | pub(crate) use metrics::IoDriverMetrics; |
399 | } |
400 | } |
401 | |
402 | cfg_not_metrics! { |
403 | pub(crate) mod metrics; |
404 | pub(crate) use metrics::{SchedulerMetrics, WorkerMetrics, MetricsBatch, HistogramBuilder}; |
405 | } |
406 | |
407 | /// After thread starts / before thread stops |
408 | type Callback = std::sync::Arc<dyn Fn() + Send + Sync>; |
409 | } |
410 | |