Spec-Zone.ru › Tokio

Функция spawn

pub fn spawn<F>(future: F) -> JoinHandle<F::Output> ⓘ
where F: Future + Send + 'static, F::Output: Send + 'static,
Доступно только при включённой возможности ящика crate feature rt.

Запускает новую асинхронную задачу и возвращает для неё JoinHandle.

Предоставленный future начнёт выполняться в фоновом режиме сразу после вызова spawn, даже если вы не будете ожидать возвращённый JoinHandle.

Запуск задачи позволяет ей выполняться одновременно с другими задачами. Запущенная задача может выполняться в текущем потоке или быть отправлена для выполнения в другой поток. Конкретное поведение зависит от конфигурации текущего Runtime. В работающей среде выполнения задача сразу начнёт выполняться в фоновом режиме. Если среда выполнения заблокирована, пользователь должен обеспечить её дальнейшую работу (например, вызвав Runtime::block_on).

Гарантируется, что spawn не будет синхронно опрашивать запускаемую задачу. Это означает, что вызов spawn при удержании блокировки не создаёт риска взаимной блокировки с запущенной задачей.

Нет гарантии, что запущенная задача выполнится до конца. При завершении работы среды выполнения все незавершённые задачи отбрасываются независимо от их жизненного цикла.

Эту функцию необходимо вызывать в контексте среды выполнения Tokio. Задачи, выполняющиеся в среде выполнения Tokio, всегда находятся в её контексте, но войти в контекст также можно с помощью метода Runtime::enter.

Примеры

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

use tokio::net::{TcpListener, TcpStream};

use std::io;

async fn process(socket: TcpStream) {
    // ...
}

#[tokio::main]
async fn main() -> io::Result<()> {
    let listener = TcpListener::bind("127.0.0.1:8080").await?;

    loop {
        let (socket, _) = listener.accept().await?;

        tokio::spawn(async move {
            // Process each socket concurrently.
            process(socket).await
        });
    }
}

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

async fn my_background_op(id: i32) -> String {
    let s = format!("Starting background task {}.", id);
    println!("{}", s);
    s
}

let ops = vec![1, 2, 3];
let mut tasks = Vec::with_capacity(ops.len());
for op in ops {
    // This call will make them start running in the background
    // immediately.
    tasks.push(tokio::spawn(my_background_op(op)));
}

let mut outputs = Vec::with_capacity(tasks.len());
for task in tasks {
    outputs.push(task.await.unwrap());
}
println!("{:?}", outputs);

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

Паники

Вызывает панику, если функция вызвана вне среды выполнения Tokio.

Использование значений !Send в задаче

Задача, передаваемая в spawn, должна реализовывать Send. Однако в задаче можно использовать значения !Send, если они существуют только между вызовами .await.

Например, следующий код будет работать:

use tokio::task;

use std::rc::Rc;

fn use_rc(rc: Rc<()>) {
    // Do stuff w/ rc
}

tokio::spawn(async {
    // Force the `Rc` to stay in a scope with no `.await`
    {
        let rc = Rc::new(());
        use_rc(rc.clone());
    }

    task::yield_now().await;
}).await.unwrap();

А следующий код не будет работать:

ⓘ
use tokio::task;

use std::rc::Rc;

fn use_rc(rc: Rc<()>) {
    // Do stuff w/ rc
}

#[tokio::main]
async fn main() {
    tokio::spawn(async {
        let rc = Rc::new(());

        task::yield_now().await;

        use_rc(rc.clone());
    }).await.unwrap();
}

Если сохранять значение !Send между вызовами .await, возникнет неудобное сообщение об ошибке компиляции, похожее на:

`[... some type ...]` cannot be sent between threads safely

или:

error[E0391]: cycle detected when processing `main`

MIT License
Copyright © Tokio Contributors
https://docs.rs/tokio/1.53.1/tokio/task/fn.spawn.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API