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

Макрос join

#![allow(unused)]
fn main() {
macro_rules! join {
    ($(biased;)? $($future:expr),*) => { ... };
}
}

Доступно только с флагом функции macros.

Ожидает завершения нескольких конкурентных ветвей, возвращая результат, когда все ветви завершатся.

Описание

Макрос join! должен использоваться внутри асинхронных функций, замыканий и блоков.

Макрос join! принимает список асинхронных выражений и выполняет их конкурентно в одной и той же задаче. Каждое асинхронное выражение вычисляется в future, и future из каждого выражения мультиплексируются в текущей задаче.

При работе с асинхронными выражениями, возвращающими Result, join! будет ждать завершения всех ветвей независимо от того, завершилась ли какая-либо из них с Err. Используйте try_join! для досрочного возврата при обнаружении Err.

Примечания

Предоставленные future хранятся inline и не требуют выделения Vec.

Характеристики времени выполнения

Поскольку все асинхронные выражения выполняются в текущей задаче, выражения могут выполняться конкурентно, но не параллельно. Это означает, что все выражения выполняются в одном потоке, и если одна ветвь блокирует поток, все другие выражения не смогут продолжить выполнение. Если требуется параллелизм, порождайте каждое асинхронное выражение с помощью tokio::spawn и передавайте дескриптор соединения в join!.

Честность (Fairness)

По умолчанию сгенерированный future макроса join! чередует порядок опроса содержащихся future при каждом пробуждении.

Это поведение можно переопределить, добавив biased; в начало использования макроса. Подробности см. в примерах. Это заставит join опрашивать future в порядке их следования сверху вниз.

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

Но у этого режима есть важное предостережение. Вы сами отвечаете за обеспечение справедливого порядка опроса ваших future. Если, например, вы объединяете поток и future завершения, и поток имеет огромный объем сообщений, обработка которых занимает много времени за один опрос, вам следует поместить future завершения раньше в списке join!, чтобы гарантировать, что он всегда будет опрашиваться и не будет задерживаться из-за того, что future потока долго возвращает Poll::Pending.

Примеры

Базовое объединение с двумя ветвями

#![allow(unused)]
fn main() {
async fn do_stuff_async() {
    // асинхронная работа
}

async fn more_async_work() {
    // больше асинхронной работы
}

let (first, second) = tokio::join!(
    do_stuff_async(),
    more_async_work()
);

// делаем что-то со значениями
}

Использование режима biased; для контроля порядка опроса

#![allow(unused)]
fn main() {
async fn do_stuff_async() {
    // асинхронная работа
}

async fn more_async_work() {
    // больше асинхронной работы
}

let (first, second) = tokio::join!(
    biased;
    do_stuff_async(),
    more_async_work()
);

// делаем что-то со значениями
}

Обработка результатов с ошибками

#![allow(unused)]
fn main() {
async fn fetch_data() -> Result<String, reqwest::Error> {
    // получение данных
}

async fn process_file() -> Result<Vec<u8>, std::io::Error> {
    // обработка файла
}

// join! будет ждать завершения обеих ветвей, даже если одна вернет Err
let (data_result, file_result) = tokio::join!(
    fetch_data(),
    process_file()
);

// Обрабатываем результаты независимо
match data_result {
    Ok(data) => println!("Данные получены: {}", data),
    Err(e) => println!("Ошибка получения данных: {}", e),
}

match file_result {
    Ok(file) => println!("Файл обработан, размер: {} байт", file.len()),
    Err(e) => println!("Ошибка обработки файла: {}", e),
}
}

Использование с разными типами возвращаемых значений

#![allow(unused)]
fn main() {
async fn get_number() -> i32 { 42 }
async fn get_text() -> &'static str { "hello" }
async fn get_vector() -> Vec<u8> { vec![1, 2, 3] }

let (number, text, vector) = tokio::join!(
    get_number(),
    get_text(),
    get_vector()
);

println!("Number: {}, Text: {}, Vector: {:?}", number, text, vector);
}