Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Структура Executor

Источник: Документация async-executor::Executor

#![allow(unused)]
fn main() {
pub struct Executor<'a> { /* private fields */ }
}

Асинхронный исполнитель (executor).

Примеры

Многопоточный исполнитель:

#![allow(unused)]
fn main() {
use async_channel::unbounded;
use async_executor::Executor;
use easy_parallel::Parallel;
use futures_lite::future;

let ex = Executor::new();
let (signal, shutdown) = unbounded::<()>();

Parallel::new()
    // Запускаем четыре потока исполнителя.
    .each(0..4, |_| future::block_on(ex.run(shutdown.recv())))
    // Запускаем основной фьючерс в текущем потоке.
    .finish(|| future::block_on(async {
        println!("Hello world!");
        drop(signal);
    }));
}

Методы

new

#![allow(unused)]
fn main() {
pub const fn new() -> Executor<'a>
}

Создает новый исполнитель.

Примеры:

#![allow(unused)]
fn main() {
use async_executor::Executor;

let ex = Executor::new();
}

is_empty

#![allow(unused)]
fn main() {
pub fn is_empty(&self) -> bool
}

Возвращает true, если нет незавершенных задач.

Примеры:

#![allow(unused)]
fn main() {
use async_executor::Executor;

let ex = Executor::new();
assert!(ex.is_empty());

let task = ex.spawn(async {
    println!("Hello world");
});
assert!(!ex.is_empty());

assert!(ex.try_tick());
assert!(ex.is_empty());
}

spawn

#![allow(unused)]
fn main() {
pub fn spawn<T>(&self, future: impl Future<Output = T> + Send + 'a) -> Task<T>
where
    T: Send + 'a,
}

Запускает задачу в исполнителе.

Примеры:

#![allow(unused)]
fn main() {
use async_executor::Executor;

let ex = Executor::new();

let task = ex.spawn(async {
    println!("Hello world");
});
}

spawn_many

#![allow(unused)]
fn main() {
pub fn spawn_many<T, F>(
    &self,
    futures: impl IntoIterator<Item = F>,
    handles: &mut impl Extend<Task<<F as Future>::Output>>,
)
where
    T: Send + 'a,
    F: Future<Output = T> + Send + 'a,
}

Запускает множество задач в исполнителе.

В отличие от метода spawn, этот метод блокирует внутреннюю блокировку задач исполнителя один раз и запускает все задачи за одну операцию. При большом количестве задач это может улучшить конкуренцию.

Пример:

#![allow(unused)]
fn main() {
use async_executor::Executor;
use futures_lite::{stream, prelude::*};
use std::future::ready;

let mut ex = Executor::new();

let futures = [
    ready(1),
    ready(2),
    ready(3)
];

// Запускаем все фьючерсы в исполнителе одновременно.
let mut tasks = vec![];
ex.spawn_many(futures, &mut tasks);

// Ожидаем завершения всех.
let results = ex.run(async move {
    stream::iter(tasks).then(|x| x).collect::<Vec<_>>().await
}).await;
assert_eq!(results, [1, 2, 3]);
}

try_tick

#![allow(unused)]
fn main() {
pub fn try_tick(&self) -> bool
}

Пытается выполнить задачу, если хотя бы одна запланирована.

Выполнение запланированной задачи означает просто однократное опрашивание ее фьючерса.

Примеры:

#![allow(unused)]
fn main() {
use async_executor::Executor;

let ex = Executor::new();
assert!(!ex.try_tick()); // нет задач для выполнения

let task = ex.spawn(async {
    println!("Hello world");
});
assert!(ex.try_tick()); // задача найдена и выполнена
}

tick

#![allow(unused)]
fn main() {
pub async fn tick(&self)
}

Выполняет одну задачу.

Выполнение задачи означает просто однократное опрашивание ее фьючерса.

Если при вызове этого метода нет запланированных задач, он будет ждать, пока одна не появится.

Примеры:

#![allow(unused)]
fn main() {
use async_executor::Executor;
use futures_lite::future;

let ex = Executor::new();

let task = ex.spawn(async {
    println!("Hello world");
});
future::block_on(ex.tick()); // выполняет задачу
}

run

#![allow(unused)]
fn main() {
pub async fn run<T>(&self, future: impl Future<Output = T>) -> T
}

Запускает исполнитель до завершения указанного фьючерса.

Примеры:

#![allow(unused)]
fn main() {
use async_executor::Executor;
use futures_lite::future;

let ex = Executor::new();

let task = ex.spawn(async { 1 + 2 });
let res = future::block_on(ex.run(async { task.await * 2 }));

assert_eq!(res, 6);
}

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

Debug

#![allow(unused)]
fn main() {
impl Debug for Executor<'_>
}
  • fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> - Форматирует значение с помощью заданного форматировщика.

Default

#![allow(unused)]
fn main() {
impl<'a> Default for Executor<'a>
}
  • fn default() -> Executor<'a> - Возвращает "значение по умолчанию" для типа.

Drop

#![allow(unused)]
fn main() {
impl Drop for Executor<'_>
}
  • fn drop(&mut self) - Выполняет деструктор для этого типа.

Маркерные трейты

  • RefUnwindSafe - Безопасен для размотки через ссылку
  • Send - Может быть передан между потоками
  • Sync - Может быть разделен между потоками
  • UnwindSafe - Безопасен для размотки

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

  • !Freeze - Не замораживается
  • Unpin - Может быть перемещено после закрепления

Стандартные реализации

ТрейтОписание
AnyПроверка типов во время выполнения
Borrow<T>Заимствование как &T
BorrowMut<T>Заимствование как &mut T
From<T>Преобразование из типа T
InstrumentИнструментирование для трассировки
Into<U>Преобразование в тип U
TryFrom<U>Попытка преобразования из типа U
TryInto<U>Попытка преобразования в тип U
WithSubscriberРабота с подписчиками

Основные методы

МетодСигнатураВозвращаемый типОписание
newpub fn new() -> Executor<'a>Executor<'a>Создает новый глобальный исполнитель
spawnpub fn spawn<T>(future: impl Future<Output = T> + Send + 'static) -> Task<T>Task<T>Запускает задачу в глобальном исполнителе
block_onpub fn block_on<T>(future: impl Future<Output = T>) -> TTБлокирует текущий поток до завершения фьючерса

Статические методы

МетодСигнатураВозвращаемый типОписание
globalpub fn global() -> &'static Executor<'static>&'static ExecutorВозвращает ссылку на глобальный исполнитель

Методы экземпляра

МетодСигнатураВозвращаемый типОписание
runpub fn run<T>(&self, future: impl Future<Output = T>) -> TTЗапускает исполнитель до завершения фьючерса
try_tickpub fn try_tick(&self) -> boolboolПытается выполнить одну задачу, если есть готовые
tickpub async fn tick(&self)()Выполняет одну задачу, ожидая если нет готовых

Зависимости типов

Основные типы

ТипИсточникНазначение
Task<T>smol::TaskПредставляет запущенную асинхронную задачу
Futurestd::future::FutureБазовый трейт для асинхронных вычислений
Executor<'a>smol::ExecutorОсновной тип исполнителя

Трейты времени выполнения

ТрейтНазначение
SendГарантирует безопасную передачу между потоками
'staticГарантирует время жизни на всю программу

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

Стандартные трейты

ТрейтРеализацияНазначение
Debugimpl Debug for Executor<'_>Отладочное представление
Defaultimpl Default for Executor<'_>Создание значения по умолчанию
Dropimpl Drop for Executor<'_>Управление временем жизни

Маркерные трейты

ТрейтНазначение
SendБезопасная передача между потоками
SyncБезопасное разделение между потоками
UnwindSafeБезопасность при размотке стека
RefUnwindSafeБезопасность ссылок при размотке

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

ТрейтОсобенности
UnpinМожет быть перемещено после закрепления
!FreezeНе может быть заморожено

Особенности использования

Глобальный исполнитель

#![allow(unused)]
fn main() {
// Получение глобального исполнителя
let executor = Executor::global();

// Запуск задачи в глобальном исполнителе
let task = executor.spawn(async {
    // асинхронный код
});
}

Локальное использование

#![allow(unused)]
fn main() {
// Создание локального исполнителя
let executor = Executor::new();

// Блокировка до завершения
executor.block_on(async {
    // асинхронный код
});
}

Ограничения и требования

  • Задачи должны реализовывать Send + 'static
  • Исполнитель предназначен для многопоточного использования
  • block_on блокирует текущий поток
  • spawn не блокирует и возвращает Task сразу