Асинхронная экосистема

На данный момент Rust предоставляет только самое необходимое для написание асинхронного кода. Важно отметить, что исполнители, задачи, реакторы, комбинаторы и низкоуровневая I/O функциональность не предоставляется стандартной библиотекой. Но асинхронные экосистемы, предоставляемые сообществом, восполняют эти пробелы.

Команда Async Foundations заинтересована в расширении примеров в Async Book для охвата нескольких сред выполнения. Если вы хотите внести свой вклад в этот проект, свяжитесь с нами через Zulip .

Асинхронные среды выполнения

Асинхронные среды выполнения — это библиотеки, используемые для выполнения асинхронных приложений. Среды выполнения обычно объединяют реактор с одним или несколькими исполнителями. Реакторы предоставляют механизмы подписки на внешние события, такие как асинхронный ввод-вывод, межпроцессное взаимодействие и таймеры. В асинхронной среде выполнения подписчиками обычно являются футуры, представляющие низкоуровневые операции ввода-вывода. Исполнители занимаются планированием и выполнением задач. Они отслеживают запущенные и приостановленные задачи, опрашивают футуры до завершения и пробуждают задачи, когда они могут продвигаться вперёд. Слово «исполнитель» часто используется как синоним «среды выполнения». Здесь мы используем слово «экосистема» для описания среды выполнения с совместимыми чертами и функциями.

Предоставленные сообществом асинхронные крейты

Крейт Futures

Крейт futures содержит трейты и функции, полезные для написания асинхронного кода. Сюда входят трейты Stream, Sink , AsyncRead и AsyncWrite, а также такие утилиты, как комбинаторы. Эти утилиты и трейты со временем могут стать частью стандартной библиотеки.

У futures есть собственный исполнитель, но нет собственного реактора, поэтому он не поддерживает выполнение асинхронного ввода-вывода или футур по таймеру. По этой причине он не считается полной средой выполнения. Обычная практика — использовать утилиты из futures с исполнителем из другого крейта.

Популярные асинхронные среды выполнения

В стандартной библиотеке нет асинхронной среды выполнения, и ни одна из них официально не рекомендована. Следующие крейты содержат популярные среды выполнения.

  • Tokio: популярная асинхронная экосистема с HTTP, gRPC и платформами отслеживания.
  • async-std: крейт, предоставляющий асинхронные аналоги компонентов стандартной библиотеки.
  • smol: небольшая упрощённая асинхронная среда выполнения. Предоставляет Async, который можно использовать обёртки таких структур, как UnixStream или TcpListener.
  • fuchsia-async: исполнитель для использования в ОС Fuchsia.

Определение совместимости экосистем

Не все асинхронные приложения, платформы и библиотеки совместимы друг с другом или с каждой ОС или платформой. Большую часть асинхронного кода можно использовать с любой экосистемой, но некоторые Фреймворки и библиотеки требуют использования определённой экосистемы. Ограничения экосистемы не всегда документируются, но есть несколько эмпирических правил, позволяющих определить, зависит ли библиотека, трейт или функция от конкретной экосистемы.

Любой асинхронный код, взаимодействующий с асинхронным вводом-выводом, таймерами, межпроцессным взаимодействием или задачами, обычно зависит от конкретного асинхронного исполнителя или реактора. Весь другой асинхронный код, такой как асинхронные выражения, комбинаторы, типы синхронизации и потоки, обычно не зависит от экосистемы, при условии, что внутренние футуры также не зависят от экосистемы. Перед началом проекта рекомендуется изучить соответствующие асинхронные платформы и библиотеки, чтобы обеспечить совместимость с выбранной вами средой выполнения и друг с другом.

Примечательно, что Tokio использует реактор mio и определяет свои собственные версии трейтов асинхронного ввода-вывода, включая AsyncRead и AsyncWrite. Сам по себе он не совместим с async-std и smol, которые полагаются на крейт async-executor, а также на AsyncRead и AsyncWrite, определённые в futures.

Конфликты зависимостей иногда можно разрешить с помощью прослойки, которая позволит вызывать код для одной среды выполнения из другой. Например, async_compat обеспечивает прослойку между Tokio и другими средами выполнения.

Библиотеки, предоставляющие асинхронные API, не должны зависеть от конкретного исполнителя или реактора, если только им не нужно порождать задачи или определять свои собственные асинхронные операции ввода-вывода или таймеры. В идеале только двоичные файлы должны отвечать за планирование и выполнение задач.

Однопоточные и многопоточные исполнители

Асинхронные исполнители могут быть однопоточными или многопоточными. Например, крейт async-executor имеет как однопоточный LocalExecutor, так и многопоточный Executor .

Многопоточный исполнитель выполняет несколько задач одновременно. Это может значительно ускорить выполнение с множеством задач, но синхронизация данных между задачами обычно обходится довольно дорого. При выборе между однопоточной и многопоточной средой выполнения рекомендуется измерять производительность вашего приложения.

Задачи могут выполняться в текущем потоке либо в отдельном. Асинхронные среды выполнения часто предоставляют возможность запуска задач в отдельном потоке, но даже тогда задачи всё равно должны быть неблокирующими. Чтобы задачи были выполнены на многопоточном исполнителе, они должны реализовывать типаж Send. Некоторые среды выполнения позволяют порождать задачи без Send, что гарантирует выполнение каждой задачи в потоке, который её породил. Они также могут предоставлять функции для порождения блокирующих задач в отдельных потоках, что полезно для запуска блокирующего синхронного кода из других библиотек.