Структура 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 | Работа с подписчиками |
Основные методы
| Метод | Сигнатура | Возвращаемый тип | Описание |
|---|---|---|---|
new | pub fn new() -> Executor<'a> | Executor<'a> | Создает новый глобальный исполнитель |
spawn | pub fn spawn<T>(future: impl Future<Output = T> + Send + 'static) -> Task<T> | Task<T> | Запускает задачу в глобальном исполнителе |
block_on | pub fn block_on<T>(future: impl Future<Output = T>) -> T | T | Блокирует текущий поток до завершения фьючерса |
Статические методы
| Метод | Сигнатура | Возвращаемый тип | Описание |
|---|---|---|---|
global | pub fn global() -> &'static Executor<'static> | &'static Executor | Возвращает ссылку на глобальный исполнитель |
Методы экземпляра
| Метод | Сигнатура | Возвращаемый тип | Описание |
|---|---|---|---|
run | pub fn run<T>(&self, future: impl Future<Output = T>) -> T | T | Запускает исполнитель до завершения фьючерса |
try_tick | pub fn try_tick(&self) -> bool | bool | Пытается выполнить одну задачу, если есть готовые |
tick | pub async fn tick(&self) | () | Выполняет одну задачу, ожидая если нет готовых |
Зависимости типов
Основные типы
| Тип | Источник | Назначение |
|---|---|---|
Task<T> | smol::Task | Представляет запущенную асинхронную задачу |
Future | std::future::Future | Базовый трейт для асинхронных вычислений |
Executor<'a> | smol::Executor | Основной тип исполнителя |
Трейты времени выполнения
| Трейт | Назначение |
|---|---|
Send | Гарантирует безопасную передачу между потоками |
'static | Гарантирует время жизни на всю программу |
Реализации трейтов
Стандартные трейты
| Трейт | Реализация | Назначение |
|---|---|---|
Debug | impl Debug for Executor<'_> | Отладочное представление |
Default | impl Default for Executor<'_> | Создание значения по умолчанию |
Drop | impl 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сразу