Spec-Zone.ru › Tokio

Структура JoinHandle

pub struct JoinHandle<T> { /* private fields */ }
Доступно только при включённой функции crate rt.

Владеющее разрешение на присоединение к задаче (ожидание её завершения).

Это можно считать эквивалентом std::thread::JoinHandle для задачи Tokio, а не потока. Обратите внимание, что фоновая задача, связанная с этим JoinHandle, начинает выполняться сразу после вызова spawn, даже если вы ещё не ожидали JoinHandle.

При удалении JoinHandle связанная задача отсоединяется, то есть дескриптора этой задачи больше не существует и её нельзя join.

Этот struct создаётся функциями task::spawn и task::spawn_blocking.

Гарантируется, что деструктор запущенной задачи завершит работу до того, как завершение задачи будет обнаружено через JoinHandle await, JoinHandle::is_finished или AbortHandle::is_finished.

Безопасность при отмене

Ожидание &mut JoinHandle<T> безопасно при отмене. Если оно используется в качестве ветви в tokio::select! и первой завершается другая ветвь, гарантируется, что результат задачи не будет потерян.

Если JoinHandle удаляется, задача продолжает выполняться в фоновом режиме, а её возвращаемое значение теряется.

Примеры

Создание с помощью task::spawn:

use tokio::task;

let join_handle: task::JoinHandle<_> = task::spawn(async {
    // some work here
});

Создание с помощью task::spawn_blocking:

use tokio::task;

let join_handle: task::JoinHandle<_> = task::spawn_blocking(|| {
    // some blocking work here
});

Параметр типа T в JoinHandle<T> — это тип возвращаемого значения запущенной задачи. Если возвращаемое значение имеет тип i32, дескриптор присоединения имеет тип JoinHandle<i32>:

use tokio::task;

let join_handle: task::JoinHandle<i32> = task::spawn(async {
    5 + 3
});

Если задача не возвращает значение, дескриптор присоединения имеет тип JoinHandle<()>:

use tokio::task;

let join_handle: task::JoinHandle<()> = task::spawn(async {
    println!("I return nothing.");
});

Обратите внимание, что handle.await не возвращает тип возвращаемого значения напрямую. Оно обёрнуто в Result, поскольку паники в запущенной задаче перехватываются Tokio. Чтобы извлечь возвращённое значение, оператор ? нужно использовать дважды:

use tokio::task;
use std::io;

let join_handle: task::JoinHandle<Result<i32, io::Error>> = tokio::spawn(async {
    Ok(5 + 3)
});

let result = join_handle.await??;
assert_eq!(result, 8);
Ok(())

Если задача завершается паникой, ошибкой будет JoinError, содержащая информацию о панике:

use tokio::task;
use std::io;
use std::panic;

#[tokio::main]
async fn main() -> io::Result<()> {
    let join_handle: task::JoinHandle<Result<i32, io::Error>> = tokio::spawn(async {
        panic!("boom");
    });

    let err = join_handle.await.unwrap_err();
    assert!(err.is_panic());
    Ok(())
}

Дочерняя задача отсоединяется и продолжает работу после завершения родительской:

use tokio::task;
use tokio::time;
use std::time::Duration;

let original_task = task::spawn(async {
    let _detached_task = task::spawn(async {
        // Here we sleep to make sure that the first task returns before.
        time::sleep(Duration::from_millis(10)).await;
        // This will be called, even though the JoinHandle is dropped.
        println!("♫ Still alive ♫");
    });
});

original_task.await.expect("The task being joined has panicked");
println!("Original task is joined.");

// We make sure that the new task has time to run, before the main
// task returns.

time::sleep(Duration::from_millis(1000)).await;

Реализации

impl<T> JoinHandle<T>

pub fn abort(&self)

Прерывает связанную с дескриптором задачу.

Ожидание отменённой задачи может завершиться как обычно, если задача уже завершилась к моменту её отмены, но, скорее всего, оно завершится ошибкой — отменённым JoinError.

Обратите внимание: задачи, запущенные с помощью spawn_blocking, нельзя прервать, поскольку они не являются асинхронными. Если вызвать abort для задачи spawn_blocking, это не окажет никакого эффекта, и задача продолжит выполняться в обычном режиме. Исключение — задача ещё не начала выполняться; в этом случае вызов abort может помешать её запуску.

Дополнительные сведения об отмене см. также в документации модуля.

use tokio::time;

let mut handles = Vec::new();

handles.push(tokio::spawn(async {
   time::sleep(time::Duration::from_secs(10)).await;
   true
}));

handles.push(tokio::spawn(async {
   time::sleep(time::Duration::from_secs(10)).await;
   false
}));

for handle in &handles {
    handle.abort();
}

for handle in handles {
    assert!(handle.await.unwrap_err().is_cancelled());
}

pub fn is_finished(&self) -> bool

Проверяет, завершилась ли задача, связанная с этим JoinHandle.

Обратите внимание: этот метод может вернуть false, даже если для задачи был вызван abort. Это связано с тем, что процесс отмены может занять некоторое время, и метод возвращает true только после его завершения.

use tokio::time;

let handle1 = tokio::spawn(async {
    // do some stuff here
});
let handle2 = tokio::spawn(async {
    // do some other stuff here
    time::sleep(time::Duration::from_secs(10)).await;
});
// Wait for the task to finish
handle2.abort();
time::sleep(time::Duration::from_secs(1)).await;
assert!(handle1.is_finished());
assert!(handle2.is_finished());

pub fn abort_handle(&self) -> AbortHandle

Возвращает новый AbortHandle, который можно использовать для удалённого прерывания этой задачи.

Ожидание задачи, отменённой с помощью AbortHandle, может завершиться как обычно, если задача уже завершилась к моменту её отмены, но, скорее всего, оно завершится ошибкой — отменённым JoinError.

use tokio::{time, task};

let mut handles = Vec::new();

handles.push(tokio::spawn(async {
   time::sleep(time::Duration::from_secs(10)).await;
   true
}));

handles.push(tokio::spawn(async {
   time::sleep(time::Duration::from_secs(10)).await;
   false
}));

let abort_handles: Vec<task::AbortHandle> = handles.iter().map(|h| h.abort_handle()).collect();

for handle in abort_handles {
    handle.abort();
}

for handle in handles {
    assert!(handle.await.unwrap_err().is_cancelled());
}

pub fn id(&self) -> Id

Возвращает идентификатор задачи, который однозначно отличает эту задачу от других задач, запущенных в данный момент.

Реализации трейтов

impl<T> Debug for JoinHandle<T>
where T: Debug,

fn fmt(&self, fmt: &mut Formatter<'_>) -> Result

Форматирует значение с помощью указанного форматтера. Подробнее

impl<T> Drop for JoinHandle<T>

fn drop(&mut self)

Выполняет деструктор этого типа. Подробнее

fn pin_drop(self: Pin<&mut Self>)

🔬Это экспериментальный API, доступный только в nightly-сборке. (pin_ergonomics)
Выполняет деструктор этого типа, но, в отличие от Drop::drop, требует, чтобы self был закреплён. Подробнее

impl<T> Future for JoinHandle<T>

type Output = Result<T, JoinError>

Тип значения, получаемого при завершении.

fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>

Пытается разрешить будущее до получения окончательного значения; если значение ещё недоступно, регистрирует текущую задачу для пробуждения. Подробнее

impl<T> RefUnwindSafe for JoinHandle<T>

impl<T: Send> Send for JoinHandle<T>

impl<T: Send> Sync for JoinHandle<T>

impl<T> Unpin for JoinHandle<T>

impl<T> UnwindSafe for JoinHandle<T>

Автоматические реализации трейтов

impl<T> Freeze for JoinHandle<T>

impl<T> UnsafeUnpin for JoinHandle<T>

Общие реализации

impl<T> Any for T
where T: 'static + ?Sized,

fn type_id(&self) -> TypeId

Получает TypeId для self. Подробнее

impl<T> Borrow<T> for T
where T: ?Sized,

fn borrow(&self) -> &T

Неизменяемо заимствует данные из принадлежащего значения. Подробнее

impl<T> BorrowMut<T> for T
where T: ?Sized,

fn borrow_mut(&mut self) -> &mut T

Изменяемо заимствует данные из принадлежащего значения. Подробнее

impl<T> From<T> for T

fn from(t: T) -> T

Возвращает аргумент без изменений.

impl<T> Instrument for T

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Инструментирует этот тип с помощью предоставленного Span, возвращая оболочку Instrumented. Подробнее

fn in_current_span(self) -> Instrumented<Self> ⓘ

Инструментирует этот тип с помощью текущего Span, возвращая оболочку Instrumented. Подробнее

impl<T, U> Into<U> for T
where U: From<T>,

fn into(self) -> U

Вызывает U::from(self).

То есть это преобразование выполняется так, как предписывает реализация From<T> for U.

impl<F> IntoFuture for F
where F: Future,

type Output = <F as Future>::Output

Результат, который будет получен при завершении будущего значения.

type IntoFuture = F

В какой тип будущего значения мы преобразуем это значение?

fn into_future(self) -> <F as IntoFuture>::IntoFuture

Создаёт будущее значение из значения. Подробнее

impl<T, U> TryFrom<U> for T
where U: Into<T>,

type Error = Infallible

Тип, возвращаемый в случае ошибки преобразования.

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Выполняет преобразование.

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

type Error = <U as TryFrom<T>>::Error

Тип, возвращаемый в случае ошибки преобразования.

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Выполняет преобразование.

impl<T> WithSubscriber for T

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Присоединяет предоставленный Subscriber к этому типу, возвращая обёртку WithDispatch. Подробнее

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Присоединяет текущий по умолчанию Subscriber к этому типу, возвращая обёртку WithDispatch. Подробнее

MIT License
Copyright © Tokio Contributors
https://docs.rs/tokio/1.53.1/tokio/task/struct.JoinHandle.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API