1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
//! Runtimes compatible with both `tokio` 0.1 and `tokio` 0.2 futures. //! //! This module is similar to the [`tokio::runtime`] module, with one //! key difference: the runtimes in this crate are capable of executing //! both `futures` 0.1 futures that use the `tokio` 0.1 runtime services //! (i.e. `timer`, `reactor`, and `executor`), **and** `std::future` //! futures that use the `tokio` 0.2 runtime services. //! //! The `futures` crate's [`compat` module][futures-compat] provides //! interoperability between `futures` 0.1 and `std::future` _future types_ //! (e.g. implementing `std::future::Future` for a type that implements the //! `futures` 0.1 `Future` trait). However, this on its own is insufficient to //! run code written against `tokio` 0.1 on a `tokio` 0.2 runtime, if that code //! also relies on `tokio`'s runtime services. If legacy tasks are executed that //! rely on `tokio::timer`, perform IO using `tokio`'s reactor, or call //! `tokio::spawn`, those API calls will fail unless there is also a runtime //! compatibility layer. //! //! `tokio-compat`'s `runtime` module contains modified versions of the `tokio` //! 0.2 `Runtime` and `current_thread::Runtime` that are capable of providing //! `tokio` 0.1 and `tokio` 0.2-compatible runtime services. //! //! Creating a [`Runtime`] does the following: //! //! * Start a [thread pool] for executing futures. //! * Run [resource drivers] for the timer and I/O resources. //! * Run a **single** `tokio` 0.1 [`Reactor`][reactor-01] and //! [`Timer`][timer-01] on a background thread, for legacy tasks. //! //! Legacy `futures` 0.1 tasks will be executed by the `tokio` 0.2 thread pool //! workers, alongside `std::future` tasks. However, they will use the timer and //! reactor provided by the compatibility background thread. //! //! ## Using the Compatibility Runtime //! //! ### Spawning //! //! In order to allow drop-in compatibility for legacy codebases using //! `tokio` 0.1, the [`run`], [`spawn`], and [`block_on`] methods provided by the //! compatibility runtimes take `futures` 0.1 futures. This allows the //! compatibility runtimes to replace the `tokio` 0.1 runtimes in those codebases //! without requiring changes to unrelated code. The compatibility runtimes //! _also_ provide `std::future`-compatible versions of these methods, named //! [`run_std`], [`spawn_std`], and [`block_on_std`]. //! //! ### Shutting Down //! //! Tokio 0.1 and Tokio 0.2 provide subtly different behavior around spawning //! tasks and shutting down runtimes. In 0.1, the threadpool and current-thread //! runtimes provide [`shutdown_on_idle`][on_idle_01] and [`run`][run_01] methods, //! respectively, which will shut the runtime down when when there are no more //! tasks currently executing. In Tokio 0.2, these methods no longer exist. //! Instead, 0.2's runtime will shut down when the future passed to `block_on` //! finishes, and the `spawn` function now returns a [`JoinHandle`], which can //! be used to await the completion of the spawned future. By awaiting these //! `JoinHandle`s, the 0.2 user now has much more fine-grained control over //! which tasks keep the runtime active. Additionally, 0.2's runtimes can avoid //! the overhead of tracking the global number of running tasks for determining //! idleness. //! //! How, then, do we bridge the gaps between these two models? The //! `tokio-compat` runtimes provide separate APIs for spawning both Tokio 0.1 //! and `Tokio` 0.2 tasks with with _and_ without `JoinHandle`s. For example, //! the `Runtime` type has the following methods: //! //! * [`Runtime::spawn`] spawns a `futures` 0.1 future, and does not return a //! `JoinHandle` (like `tokio` 0.1). //! * [`Runtime::spawn_std`] spawns a `std::future` future, and does not return //! a `JoinHandle`. //! * [`Runtime::spawn_handle`] spawns a `futures` 0.1 future, and returns a //! `JoinHandle`. //! * [`Runtime::spawn_handle_std`] spawns a `std::future` future, and returns a //! `JoinHandle` (like `tokio` 0.2). //! //! Other types which spawn futures, like [`TaskExecutor`], provide similar APIs. //! //! The `tokio-compat` current-thread and thread pool runtimes also provide //! their own versions of `run` and `shutdown_on_idle`, respectively. However, //! **only tasks spawned without `JoinHandle`s** "count" against idleness. This //! means that if a task is spawned by a function returning a `JoinHandle`, it //! will **not** keep the runtime active if no other tasks are running. //! //! Why is this the case? There are two primary reasons: //! //! 1. The `shutdown_on_idle` and `run` methods no longer exist in `tokio` 0.2. //! Therefore, codebases transitioning from 0.1 to 0.2 will no longer be able //! to use these APIs when they are fully transitioned to 0.2. Therefore, //! the compatibility runtime provides them to enable incremental transitions //! to the new APIs, but ideally, code using them should *eventually* be //! rewritten to use the new style. //! 2. In order to implement idleness tracking on the compatibility runtimes, it //! is necessary to override the behavior of `tokio::spawn`. This is possible //! in Tokio 0.1, using [`executor::with_default`], so we are able to track //! idleness of futures spawned via 0.1's `tokio::spawn`. However, Tokio 0.2 //! does not allow overriding spawn's behavior, so we are **not** able to //! track the idleness of futures spawned by 0.2's `tokio::spawn`. Therefore, //! in order to provide a consistent API, `tokio-compat` makes a distinction //! between tasks spawned with and without `JoinHandle`s. //! //! For reference, spawning tasks via the following functions **will** count to //! keep the runtime active in `run` or `shutdown_on_idle`: //! //! * [`Runtime::spawn`] and [`current_thread::Runtime::spawn`] //! * [`Runtime::spawn_std`] and [`current_thread::Runtime::spawn_std`] //! * [`TaskExecutor::spawn`] and [`current_thread::TaskExecutor::spawn_local`] //! * [`TaskExecutor::spawn_std`] and [`current_thread::TaskExecutor::spawn_local_std`] //! * [`current_thread::Handle::spawn`] and [`current_thread::Handle::spawn_std`] //! * All implementations of `tokio` 0.1's [`Executor`] and [`TypedExecutor`] //! traits for types defined in `tokio-compat`. //! * [`tokio::spawn`][spawn_01] **from the 0.1 version of `tokio`** //! * `tokio` 0.1's [`DefaultExecutor`] //! //! Meanwhile, the tasks spawned by the these functions will **not** count to //! keep the runtime active, and return `JoinHandle`s that must be `await`ed //! instead: //! //! * [`Runtime::spawn_handle`] and [`current_thread::Runtime::spawn_handle`] //! * [`Runtime::spawn_handle_std`] and [`current_thread::Runtime::spawn_handle_std`] //! * [`TaskExecutor::spawn_handle`] and [`current_thread::TaskExecutor::spawn_handle`] //! * [`TaskExecutor::spawn_handle`] and [`current_thread::TaskExecutor::spawn_handle_std`] //! * [`current_thread::Handle::spawn_handle`] and [`current_thread::Handle::spawn_handle_std`] //! * [`tokio::spawn`][spawn_02], [`tokio::task::spawn_local`], and //! [`tokio::task::spawn_blocking`] **from the 0.2 version of `tokio`** //! //! [`JoinHandle`]: https://docs.rs/tokio/0.2.4/tokio/task/struct.JoinHandle.html //! [`Runtime::spawn`]: struct.Runtime.html#method.spawn //! [`Runtime::spawn_std`]: struct.Runtime.html#method.spawn_std //! [`Runtime::spawn_handle`]: struct.Runtime.html#method.spawn_handle //! [`Runtime::spawn_handle_std`]: struct.Runtime.html#method.spawn_handle_std //! [`TaskExecutor`]: struct.TaskExecutor.html //! [`TaskExecutor::spawn`]: struct.TaskExecutor.html#method.spawn //! [`TaskExecutor::spawn_std`]: struct.TaskExecutor.html#method.spawn_std //! [`TaskExecutor::spawn_handle`]: struct.TaskExecutor.html#method.spawn_handle //! [`current_thread::Runtime::spawn`]: current_thread/struct.Runtime.html#method.spawn //! [`current_thread::Runtime::spawn_std`]: current_thread/struct.Runtime.html#method.spawn_std //! [`current_thread::Runtime::spawn_handle`]: current_thread/struct.Runtime.html#method.spawn_handle //! [`current_thread::Runtime::spawn_handle_std`]: current_thread/struct.Runtime.html#method.spawn_handle_std //! [`current_thread::TaskExecutor::spawn_local`]: current_thread/struct.TaskExecutor.html#method.spawn_local_std //! [`current_thread::TaskExecutor::spawn_local_std`]: current_thread/struct.TaskExecutor.html#method.spawn_local_std //! [`current_thread::TaskExecutor::spawn_handle`]: current_thread/struct.TaskExecutor.html#method.spawn_handle //! [`current_thread::TaskExecutor::spawn_handle_std`]: current_thread/struct.TaskExecutor.html#method.spawn_handle_std //! [`current_thread::Handle::spawn`]: current_thread/struct.Handle.html#method.spawn //! [`current_thread::Handle::spawn_std`]: current_thread/struct.Handle.html#method.spawn_std //! [`current_thread::Handle::spawn_handle`]: current_thread/struct.Handle.html#method.spawn_handle //! [`current_thread::Handle::spawn_handle_std`]: current_thread/struct.Handle.html#method.spawn_handle_std //! [`Executor`]: https://docs.rs/tokio/0.1.22/tokio/executor/trait.Executor.html //! [`TypedExecutor`]: https://docs.rs/tokio/0.1.22/tokio/executor/trait.TypedExecutor.html //! [`DefaultExecutor`]: https://docs.rs/tokio/0.1.22/tokio/executor/struct.DefaultExecutor.html //! [spawn_01]: https://docs.rs/tokio/0.1.22/tokio/executor/fn.spawn.html //! [spawn_02]: https://docs.rs/tokio/0.2.4/tokio/fn.spawn.html //! [run_01]: https://docs.rs/tokio/0.1.22/tokio/runtime/current_thread/struct.Runtime.html#method.run.html //! [on_idle_01]: https://docs.rs/tokio/0.1.22/tokio/runtime/struct.Runtime.html#method.shutdown_on_idle.html //! [`tokio::task::spawn_local`]: https://docs.rs/tokio/0.2.4/tokio/task/fn.spawn_local.html //! [`tokio::task::spawn_blocking`]: https://docs.rs/tokio/0.2.4/tokio/task/fn.spawn_blocking.html //! [`executor::with_default`]: https://docs.rs/tokio-executor/0.1.9/tokio_executor/fn.with_default.html //! //! ### Blocking //! //! The compatibility thread pool runtime does **not** currently support the //! `tokio` 0.1 [`tokio_threadpool::blocking`][blocking] API. Calls to the //! legacy version of `blocking` made on the compatibility runtime will currently //! fail. In the future, `tokio-compat` will allow transparently replacing //! legacy `blocking` with the `tokio` 0.2 blocking APIs, but in the meantime, //! it will be necessary to convert this code to call into the `tokio` 0.2 //! [`task::block_in_place`] and [`task::spawn_blocking`] APIs instead. //! //! [blocking]: https://docs.rs/tokio-threadpool/0.1.16/tokio_threadpool/fn.blocking.html //! [`task::block_in_place`]: https://docs.rs/tokio/0.2.4/tokio/task/fn.block_in_place.html //! [`task::spawn_blocking`]: https://docs.rs/tokio/0.2.4/tokio/task/fn.spawn_blocking.html //! //! ## Examples //! //! Spawning both `tokio` 0.1 and `tokio` 0.2 futures: //! //! ```rust //! use futures_01::future::lazy; //! //! tokio_compat::run(lazy(|| { //! // spawn a `futures` 0.1 future using the `spawn` function from the //! // `tokio` 0.1 crate: //! tokio_01::spawn(lazy(|| { //! println!("hello from tokio 0.1!"); //! Ok(()) //! })); //! //! // spawn an `async` block future on the same runtime using `tokio` //! // 0.2's `spawn`: //! tokio_02::spawn(async { //! println!("hello from tokio 0.2!"); //! }); //! //! Ok(()) //! })) //! ``` //! //! Futures on the compat runtime can use `timer` APIs from both 0.1 and 0.2 //! versions of `tokio`: //! //! ```rust //! # use std::time::{Duration, Instant}; //! use tokio_compat::prelude::*; //! //! tokio_compat::run_std(async { //! // Wait for a `tokio` 0.1 `Delay`... //! let when = Instant::now() + Duration::from_millis(10); //! tokio_01::timer::Delay::new(when) //! // convert the delay future into a `std::future` that we can `await`. //! .compat() //! .await //! .expect("tokio 0.1 timer should work!"); //! println!("10 ms have elapsed"); //! //! // Wait for a `tokio` 0.2 `Delay`... //! tokio_02::time::delay_for(Duration::from_millis(20)).await; //! println!("20 ms have elapsed"); //! }); //! ``` //! //! [`tokio::runtime`]: https://docs.rs/tokio/0.2.4/tokio/runtime/index.html //! [futures-compat]: https://rust-lang-nursery.github.io/futures-api-docs/0.3.0-alpha.19/futures/compat/index.html //! [`Runtime`]: struct.Runtime.html //! [resource drivers]: https://docs.rs/tokio/0.2.4/tokio/runtime/index.html#resource-drivers //! [thread pool]: https://docs.rs/tokio/0.2.4/tokio/runtime/index.html#threaded-scheduler //! [timer-01]: https://docs.rs/tokio/0.1.22/tokio/timer/index.html //! [reactor-01]: https://docs.rs/tokio/0.1.22/tokio/reactor/struct.Reactor.html //! [`run`]: struct.Runtime.html#method.run //! [`spawn`]: struct.Runtime.html#method.spawn //! [`block_on`]: struct.Runtime.html#method.block_on //! [`run_std`]: struct.Runtime.html#method.run_std //! [`spawn_std`]: struct.Runtime.html#method.spawn_std //! [`block_on_std`]: struct.Runtime.html#method.spawn_std mod compat; #[cfg(feature = "rt-current-thread")] pub mod current_thread; mod idle; #[cfg(feature = "rt-full")] mod threadpool; #[cfg(feature = "rt-full")] pub use threadpool::{run, run_std, Builder, Runtime, TaskExecutor};