pub struct Handle { /* private fields */ }rt only.Expand description
Handle to the runtime.
The handle is internally reference-counted and can be freely cloned. A handle can be
obtained using the Runtime::handle method.
Implementations§
Source§impl Handle
impl Handle
Sourcepub fn enter(&self) -> EnterGuard<'_>
pub fn enter(&self) -> EnterGuard<'_>
Enters the runtime context. This allows you to construct types that must
have an executor available on creation such as Sleep or
TcpStream. It will also allow you to call methods such as
tokio::spawn and Handle::current without panicking.
§Panics
When calling Handle::enter multiple times, the returned guards
must be dropped in the reverse order that they were acquired.
Failure to do so will result in a panic and possible memory leaks.
§Examples
use tokio::runtime::Runtime;
let rt = Runtime::new().unwrap();
let _guard = rt.enter();
tokio::spawn(async {
println!("Hello world!");
});Do not do the following, this shows a scenario that will result in a panic and possible memory leak.
use tokio::runtime::Runtime;
let rt1 = Runtime::new().unwrap();
let rt2 = Runtime::new().unwrap();
let enter1 = rt1.enter();
let enter2 = rt2.enter();
drop(enter1);
drop(enter2);Sourcepub fn current() -> Self
pub fn current() -> Self
Returns a Handle view over the currently running Runtime.
§Panics
This will panic if called outside the context of a Tokio runtime. That means that you must
call this on one of the threads being run by the runtime, or from a thread with an active
EnterGuard. Calling this from within a thread created by std::thread::spawn (for example)
will cause a panic unless that thread has an active EnterGuard.
§Examples
This can be used to obtain the handle of the surrounding runtime from an async block or function running on that runtime.
use tokio::runtime::Handle;
// Inside an async block or function.
let handle = Handle::current();
handle.spawn(async {
println!("now running in the existing Runtime");
});
thread::spawn(move || {
// Notice that the handle is created outside of this thread and then moved in
handle.spawn(async { /* ... */ });
// This next line would cause a panic because we haven't entered the runtime
// and created an EnterGuard
// let handle2 = Handle::current(); // panic
// So we create a guard here with Handle::enter();
let _guard = handle.enter();
// Now we can call Handle::current();
let handle2 = Handle::current();
});Sourcepub fn try_current() -> Result<Self, TryCurrentError>
pub fn try_current() -> Result<Self, TryCurrentError>
Returns a Handle view over the currently running Runtime
Returns an error if no Runtime has been started
Contrary to current, this never panics
Sourcepub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output> ⓘ
pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output> ⓘ
Spawns a future onto the Tokio runtime.
This spawns the given future onto the runtime’s executor, usually a thread pool. The thread pool is then responsible for polling the future until it completes.
The provided future will start running in the background immediately
when spawn is called, even if you don’t await the returned
JoinHandle (assuming that the runtime is running).
See module level documentation for more details.
§Examples
use tokio::runtime::Runtime;
// Create the runtime
let rt = Runtime::new().unwrap();
// Get a handle from this runtime
let handle = rt.handle();
// Spawn a future onto the runtime using the handle
handle.spawn(async {
println!("now running on a worker thread");
});Sourcepub fn spawn_blocking<F, R>(&self, func: F) -> JoinHandle<R> ⓘ
pub fn spawn_blocking<F, R>(&self, func: F) -> JoinHandle<R> ⓘ
Runs the provided function on an executor dedicated to blocking operations.
§Examples
use tokio::runtime::Runtime;
// Create the runtime
let rt = Runtime::new().unwrap();
// Get a handle from this runtime
let handle = rt.handle();
// Spawn a blocking function onto the runtime using the handle
handle.spawn_blocking(|| {
println!("now running on a worker thread");
});Sourcepub fn block_on<F: Future>(&self, future: F) -> F::Output
pub fn block_on<F: Future>(&self, future: F) -> F::Output
Runs a future to completion on this Handle’s associated Runtime.
This runs the given future on the current thread, blocking until it is complete, and yielding its resolved result. Any tasks or timers which the future spawns internally will be executed on the runtime.
When this is used on a current_thread runtime, only the
Runtime::block_on method can drive the IO and timer drivers, but the
Handle::block_on method cannot drive them. This means that, when using
this method on a current_thread runtime, anything that relies on IO or
timers will not work unless there is another thread currently calling
Runtime::block_on on the same runtime.
§If the runtime has been shut down
If the Handle’s associated Runtime has been shut down (through
Runtime::shutdown_background, Runtime::shutdown_timeout, or by
dropping it) and Handle::block_on is used it might return an error or
panic. Specifically IO resources will return an error and timers will
panic. Runtime independent futures will run as normal.
§Panics
This function will panic if any of the following conditions are met:
- The provided future panics.
- It is called from within an asynchronous context, such as inside
Runtime::block_on,Handle::block_on, or from a function annotated withtokio::main. - A timer future is executed on a runtime that has been shut down.
§Examples
use tokio::runtime::Runtime;
// Create the runtime
let rt = Runtime::new().unwrap();
// Get a handle from this runtime
let handle = rt.handle();
// Execute the future, blocking the current thread until completion
handle.block_on(async {
println!("hello");
});Or using Handle::current:
use tokio::runtime::Handle;
#[tokio::main]
async fn main () {
let handle = Handle::current();
std::thread::spawn(move || {
// Using Handle::block_on to run async code in the new thread.
handle.block_on(async {
println!("hello");
});
});
}Handle::block_on may be combined with task::block_in_place to
re-enter the async context of a multi-thread scheduler runtime:
use tokio::task;
use tokio::runtime::Handle;
task::block_in_place(move || {
Handle::current().block_on(async move {
// do something async
});
});Sourcepub fn runtime_flavor(&self) -> RuntimeFlavor
pub fn runtime_flavor(&self) -> RuntimeFlavor
Returns the flavor of the current Runtime.
§Examples
use tokio::runtime::{Handle, RuntimeFlavor};
#[tokio::main(flavor = "current_thread")]
async fn main() {
assert_eq!(RuntimeFlavor::CurrentThread, Handle::current().runtime_flavor());
}use tokio::runtime::{Handle, RuntimeFlavor};
#[tokio::main(flavor = "multi_thread", worker_threads = 4)]
async fn main() {
assert_eq!(RuntimeFlavor::MultiThread, Handle::current().runtime_flavor());
}Sourcepub fn metrics(&self) -> RuntimeMetrics
pub fn metrics(&self) -> RuntimeMetrics
Returns a view that lets you get information about how the runtime is performing.
Source§impl Handle
impl Handle
Sourcepub async fn dump(&self) -> Dump
pub async fn dump(&self) -> Dump
Captures a snapshot of the runtime’s state.
If you only want to capture a snapshot of a single future’s state, you can use
Trace::capture.
This functionality is experimental, and comes with a number of requirements and limitations.
§Examples
This can be used to get call traces of each task in the runtime.
Calls to Handle::dump should usually be enclosed in a
timeout, so that dumping does not escalate a
single blocked runtime thread into an entirely blocked runtime.
use tokio::runtime::Handle;
use tokio::time::{timeout, Duration};
// Inside an async block or function.
let handle = Handle::current();
if let Ok(dump) = timeout(Duration::from_secs(2), handle.dump()).await {
for (i, task) in dump.tasks().iter().enumerate() {
let trace = task.trace();
println!("TASK {i}:");
println!("{trace}\n");
}
}This produces highly detailed traces of tasks; e.g.:
TASK 0:
╼ dump::main::{{closure}}::a::{{closure}} at /tokio/examples/dump.rs:18:20
└╼ dump::main::{{closure}}::b::{{closure}} at /tokio/examples/dump.rs:23:20
└╼ dump::main::{{closure}}::c::{{closure}} at /tokio/examples/dump.rs:28:24
└╼ tokio::sync::barrier::Barrier::wait::{{closure}} at /tokio/tokio/src/sync/barrier.rs:129:10
└╼ <tokio::util::trace::InstrumentedAsyncOp<F> as core::future::future::Future>::poll at /tokio/tokio/src/util/trace.rs:77:46
└╼ tokio::sync::barrier::Barrier::wait_internal::{{closure}} at /tokio/tokio/src/sync/barrier.rs:183:36
└╼ tokio::sync::watch::Receiver<T>::changed::{{closure}} at /tokio/tokio/src/sync/watch.rs:604:55
└╼ tokio::sync::watch::changed_impl::{{closure}} at /tokio/tokio/src/sync/watch.rs:755:18
└╼ <tokio::sync::notify::Notified as core::future::future::Future>::poll at /tokio/tokio/src/sync/notify.rs:1103:9
└╼ tokio::sync::notify::Notified::poll_notified at /tokio/tokio/src/sync/notify.rs:996:32§Requirements
§Debug Info Must Be Available
To produce task traces, the application must not be compiled
with split debuginfo. On Linux, including debuginfo within the
application binary is the (correct) default. You can further ensure
this behavior with the following directive in your Cargo.toml:
[profile.*]
split-debuginfo = "off"§Unstable Features
This functionality is unstable, and requires both the
--cfg tokio_unstable and cargo feature taskdump to be set.
You can do this by setting the RUSTFLAGS environment variable
before invoking cargo; e.g.:
RUSTFLAGS="--cfg tokio_unstable cargo run --example dumpOr by configuring rustflags in
.cargo/config.toml:
[build]
rustflags = ["--cfg", "tokio_unstable"]§Platform Requirements
Task dumps are supported on Linux atop aarch64, x86 and x86_64.
§Current Thread Runtime Requirements
On the current_thread runtime, task dumps may only be requested
from within the context of the runtime being dumped. Do not, for
example, await Handle::dump() on a different runtime.
§Limitations
§Performance
Although enabling the taskdump feature imposes virtually no
additional runtime overhead, actually calling Handle::dump is
expensive. The runtime must synchronize and pause its workers, then
re-poll every task in a special tracing mode. Avoid requesting dumps
often.
§Local Executors
Tasks managed by local executors (e.g., FuturesUnordered and
LocalSet) may not appear in task dumps.
§Non-Termination When Workers Are Blocked
The future produced by Handle::dump may never produce Ready if
another runtime worker is blocked for more than 250ms. This may
occur if a dump is requested during shutdown, or if another runtime
worker is infinite looping or synchronously deadlocked. For these
reasons, task dumping should usually be paired with an explicit
timeout.