[][src]Module tokio_compat::runtime

This is supported on feature="rt-current-thread" or feature="rt-full" only.

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

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 and run 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 JoinHandles, 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 JoinHandles. For example, the Runtime type has the following methods:

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 JoinHandles "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 JoinHandles.

For reference, spawning tasks via the following functions will count to keep the runtime active in run or shutdown_on_idle:

Meanwhile, the tasks spawned by the these functions will not count to keep the runtime active, and return JoinHandles that must be awaited instead:

Blocking

The compatibility thread pool runtime does not currently support the tokio 0.1 tokio_threadpool::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.

Examples

Spawning both tokio 0.1 and tokio 0.2 futures:

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:

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");
});

Modules

current_threadfeature="rt-current-thread" or feature="rt-full"

A compatibility implementation that runs everything on the current thread.

Structs

Builder(feature="rt-current-thread" or feature="rt-full") and feature="rt-full"

Builds a compatibility runtime with custom configuration values.

Runtime(feature="rt-current-thread" or feature="rt-full") and feature="rt-full"

A thread pool runtime that can run tasks that use both tokio 0.1 and tokio 0.2 APIs.

TaskExecutor(feature="rt-current-thread" or feature="rt-full") and feature="rt-full"

Executes futures on the runtime

Functions

run(feature="rt-current-thread" or feature="rt-full") and feature="rt-full"

Start the Tokio runtime using the supplied futures 0.1 future to bootstrap execution.

run_std(feature="rt-current-thread" or feature="rt-full") and feature="rt-full"

Start the Tokio runtime using the supplied std::future future to bootstrap execution.