Структура Handle
pub struct Handle { /* private fields */ }
rt.Дескриптор среды выполнения.
Дескриптор внутри реализован с подсчётом ссылок, поэтому его можно свободно клонировать. Дескриптор можно получить с помощью метода Runtime::handle.
Реализации
impl Handle
pub fn enter(&self) -> EnterGuard<'_>
Входит в контекст среды выполнения. Это позволяет создавать типы, которым при создании необходим доступный исполнитель, например Sleep или TcpStream. Также это позволит вызывать такие методы, как tokio::spawn и Handle::current, не вызывая паники.
Паники
При многократном вызове Handle::enter возвращённые охранные объекты должны удаляться в обратном порядке относительно порядка их получения. Несоблюдение этого требования приведёт к панике и возможным утечкам памяти.
Примеры
use tokio::runtime::Runtime;
let rt = Runtime::new().unwrap();
let _guard = rt.enter();
tokio::spawn(async {
println!("Hello world!");
});Не делайте следующего: этот пример демонстрирует ситуацию, которая приведёт к панике и возможной утечке памяти.
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);
pub fn current() -> Self
Возвращает представление Handle текущей работающей Runtime.
Паники
Этот вызов приведёт к панике, если выполняется вне контекста среды выполнения Tokio. Это означает, что вы должны вызвать его в одном из потоков, выполняемых средой выполнения, или из потока с активным EnterGuard. Вызов из потока, созданного, например, с помощью std::thread::spawn, приведёт к панике, если в этом потоке нет активного EnterGuard.
Примеры
Это можно использовать для получения дескриптора окружающей среды выполнения из асинхронного блока или функции, выполняющейся в этой среде.
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();
});pub fn try_current() -> Result<Self, TryCurrentError>
Возвращает представление Handle текущей работающей Runtime.
Возвращает ошибку, если Runtime не была запущена.
В отличие от current, этот вызов никогда не приводит к панике.
pub fn spawn<F>(&self, future: F) -> JoinHandle<F::Output> ⓘ
Запускает future в среде выполнения Tokio.
Переданный future запускается в исполнителе среды выполнения, обычно в пуле потоков. Затем пул потоков отвечает за опрос future до его завершения.
Переданный future немедленно начинает выполняться в фоновом режиме при вызове spawn, даже если вы не ожидаете завершения возвращённого JoinHandle (при условии, что среда выполнения работает).
Подробнее см. в документации на уровне модуля.
Примеры
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");
});pub fn spawn_blocking<F, R>(&self, func: F) -> JoinHandle<R> ⓘ
Запускает переданную функцию в исполнителе, предназначенном для блокирующих операций.
Примеры
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");
});pub fn block_on<F: Future>(&self, future: F) -> F::Output
Запускает future до завершения в связанной Runtime этой Handle.
Указанная future выполняется в текущем потоке: выполнение блокируется до её завершения, после чего возвращается полученный результат. Все задачи и таймеры, создаваемые future, будут выполняться в среде выполнения.
При использовании этого метода в среде выполнения current_thread только метод Runtime::block_on может управлять драйверами ввода-вывода и таймеров, а метод Handle::block_on — нет. Это означает, что при использовании этого метода в среде выполнения current_thread всё, что зависит от ввода-вывода или таймеров, не будет работать, если в другом потоке одновременно не вызывается Runtime::block_on для той же среды выполнения.
Если работа среды выполнения была остановлена
Если связанная Runtime этой Handle была остановлена (с помощью Runtime::shutdown_background, Runtime::shutdown_timeout или при её удалении), использование Handle::block_on может привести к ошибке или панике. В частности, ресурсы ввода-вывода вернут ошибку, а таймеры вызовут панику. Future, не зависящие от среды выполнения, продолжат выполняться как обычно.
Паники
Эта функция вызовет панику при выполнении любого из следующих условий:
- Предоставленная future вызывает панику.
- Функция вызывается из асинхронного контекста, например внутри
Runtime::block_on,Handle::block_onили из функции, помеченной атрибутомtokio::main. - Future таймера выполняется в остановленной среде выполнения.
Примеры
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");
});Или с использованием 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 можно использовать вместе с task::block_in_place, чтобы повторно войти в асинхронный контекст среды выполнения с многопоточным планировщиком:
use tokio::task;
use tokio::runtime::Handle;
task::block_in_place(move || {
Handle::current().block_on(async move {
// do something async
});
});pub fn runtime_flavor(&self) -> RuntimeFlavor
Возвращает тип текущей среды выполнения Runtime.
Примеры
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());
}pub fn id(&self) -> Id
Возвращает Id текущей среды выполнения Runtime.
Примеры
use tokio::runtime::Handle;
#[tokio::main(flavor = "current_thread")]
async fn main() {
println!("Current runtime id: {}", Handle::current().id());
}pub fn name(&self) -> Option<&str>
Возвращает имя текущей среды выполнения Runtime.
Примеры
use tokio::runtime::Handle;
#[tokio::main(flavor = "current_thread", name = "my-runtime")]
async fn main() {
println!("Current runtime name: {}", Handle::current().name().unwrap());
}pub fn metrics(&self) -> RuntimeMetrics
Возвращает представление, позволяющее получить сведения о производительности среды выполнения.
impl Handle
pub async fn dump(&self) -> Dump
tokio_unstable и Linux, при включённой возможности crate taskdump и на платформах (AArch64, s390x, x86 или x86-64).Создаёт снимок состояния среды выполнения.
Если нужно создать снимок состояния только одного future, можно использовать Trace::capture.
Эта функциональность является экспериментальной и имеет ряд требований и ограничений.
Примеры
Это можно использовать для получения трасс вызовов каждой задачи в среде выполнения. Вызовы Handle::dump обычно следует оборачивать в тайм-аут, чтобы создание дампа не превратило блокировку одного потока среды выполнения в блокировку всей среды выполнения.
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");
}
}В результате получаются подробные трассы задач, например:
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Требования
Отладочная информация должна быть доступна
Для создания трасс задач приложение не должно компилироваться с split debuginfo. В Linux включение debuginfo в двоичный файл приложения является (правильным) поведением по умолчанию. Дополнительно обеспечить это поведение можно с помощью следующей директивы в Cargo.toml:
[profile.*]
split-debuginfo = "off"Нестабильные возможности
Эта функциональность нестабильна и требует включения как --cfg tokio_unstable, так и возможности Cargo taskdump.
Для этого задайте переменную окружения RUSTFLAGS перед вызовом cargo; например:
RUSTFLAGS="--cfg tokio_unstable" cargo run --example dumpИли настройте rustflags в .cargo/config.toml:
[build]
rustflags = ["--cfg", "tokio_unstable"]Требования к платформе
Дампы задач поддерживаются в Linux на базе aarch64, x86, x86_64 и s390x.
Требования для среды выполнения с одним потоком
В среде выполнения current_thread запрашивать дампы задач можно только внутри контекста среды выполнения, для которой создаётся дамп. Например, не следует ожидать завершения Handle::dump() в другой среде выполнения.
Ограничения
Производительность
Хотя включение возможности taskdump практически не создаёт дополнительной нагрузки на среду выполнения, вызов Handle::dump требует значительных затрат. Среда выполнения должна синхронизировать и приостановить рабочие потоки, а затем повторно опросить каждую задачу в специальном режиме трассировки. Не запрашивайте дампы слишком часто.
Локальные исполнители
Задачи, которыми управляют локальные исполнители (например, FuturesUnordered и LocalSet), могут не отображаться в дампах задач.
Незавершение работы при блокировке рабочих потоков
Future, созданный с помощью Handle::dump, может никогда не выдать Ready, если другой рабочий поток среды выполнения заблокирован более чем на 250 мс. Такое может произойти, если дамп запрашивается во время завершения работы или если другой рабочий поток среды выполнения бесконечно выполняет цикл либо синхронно заблокирован. Поэтому создание дампов задач обычно следует сочетать с явным тайм-аутом.
Реализации трейтов
impl RefUnwindSafe for Handle
impl UnwindSafe for Handle
Автоматические реализации трейтов
impl Freeze for Handle
impl Send for Handle
impl Sync for Handle
impl Unpin for Handle
impl UnsafeUnpin for Handle
Обобщённые реализации
impl<T> BorrowMut<T> for Twhere T: ?Sized,
fn borrow_mut(&mut self) -> &mut T
impl<T> CloneToUninit for Twhere T: Clone,
unsafe fn clone_to_uninit(&self, dest: *mut u8)
clone_to_uninit)
impl<T> Instrument for T
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
impl<T> ToOwned for Twhere T: Clone,
type Owned = T
fn to_owned(&self) -> T
fn clone_into(&self, target: &mut T)
impl<T> WithSubscriber for T
fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ
Subscriber к этому типу и возвращает обёртку WithDispatch. Подробнее
MIT License
Copyright © Tokio Contributors
https://docs.rs/tokio/1.53.1/tokio/runtime/struct.Handle.html