Макрос try_ join
macro_rules! try_join {
($(biased;)? $($future:expr),*) => { ... };
}
macros.Ожидает завершения нескольких одновременно выполняющихся ветвей, возвращая результат, когда все ветви завершаются с Ok(_), или при первом Err(_).
Макрос try_join! необходимо использовать внутри асинхронных функций, замыканий и блоков.
Как и join!, макрос try_join! принимает список асинхронных выражений и вычисляет их одновременно в рамках одной задачи. Каждое асинхронное выражение вычисляется в future, а future из каждого выражения мультиплексируются в текущей задаче. Макрос try_join! возвращает результат, когда все ветви завершаются с Ok или когда первая ветвь завершается с Err.
Примечания
Переданные future хранятся непосредственно и не требуют выделения Vec.
Особенности работы
Запуская все асинхронные выражения в текущей задаче, эти выражения могут выполняться одновременно, но не параллельно. Это означает, что все выражения выполняются в одном потоке, и если одна ветвь блокирует поток, все остальные выражения не смогут продолжить работу. Если требуется параллельное выполнение, запустите каждое асинхронное выражение с помощью tokio::spawn и передайте макросу try_join! дескриптор объединения.
Справедливость
По умолчанию future, создаваемый макросом try_join!, при каждом пробуждении меняет порядок опроса содержащихся в нём future, выбирая другой future для первого опроса.
Это поведение можно переопределить, добавив biased; в начало вызова макроса. Подробности см. в примерах. В этом случае try_join будет опрашивать future в порядке их появления сверху вниз.
Это может быть полезно, если future могут взаимодействовать таким образом, что важен известный порядок опроса.
Однако у этого режима есть важная оговорка. Вы сами отвечаете за обеспечение справедливого порядка опроса future. Например, если вы объединяете поток и future завершения работы, а в потоке содержится огромное количество сообщений, обработка которых при каждом опросе занимает много времени, следует поместить future завершения работы раньше в списке try_join!, чтобы он всегда опрашивался и не задерживался из-за того, что future потока долго не возвращает Poll::Pending.
Примеры
Простой пример try_join с двумя ветвями.
async fn do_stuff_async() -> Result<(), &'static str> {
// async work
}
async fn more_async_work() -> Result<(), &'static str> {
// more here
}
let res = tokio::try_join!(
do_stuff_async(),
more_async_work());
match res {
Ok((first, second)) => {
// do something with the values
}
Err(err) => {
println!("processing failed; error = {}", err);
}
}Использование try_join! с запущенными задачами.
use tokio::task::JoinHandle;
async fn do_stuff_async() -> Result<(), &'static str> {
// async work
}
async fn more_async_work() -> Result<(), &'static str> {
// more here
}
async fn flatten<T>(handle: JoinHandle<Result<T, &'static str>>) -> Result<T, &'static str> {
match handle.await {
Ok(Ok(result)) => Ok(result),
Ok(Err(err)) => Err(err),
Err(err) => Err("handling failed"),
}
}
let handle1 = tokio::spawn(do_stuff_async());
let handle2 = tokio::spawn(more_async_work());
match tokio::try_join!(flatten(handle1), flatten(handle2)) {
Ok(val) => {
// do something with the values
}
Err(err) => {
println!("Failed with {}.", err);
}
}Использование режима biased; для управления порядком опроса.
async fn do_stuff_async() -> Result<(), &'static str> {
// async work
}
async fn more_async_work() -> Result<(), &'static str> {
// more here
}
let res = tokio::try_join!(
biased;
do_stuff_async(),
more_async_work()
);
match res {
Ok((first, second)) => {
// do something with the values
}
Err(err) => {
println!("processing failed; error = {}", err);
}
}
MIT License
Copyright © Tokio Contributors
https://docs.rs/tokio/1.53.1/tokio/macro.try_join.html