跳到主要内容

spawn

搜索

函数 spawn 

Source
pub fn spawn<F>(future: F) -> JoinHandle<F::Output> 
where F: Future + Send + 'static, F::Output: Send + 'static,
展开描述

生成一个新的异步 task,返回一个 JoinHandle

当调用 spawn 时, 所提供的 future 将立即开始在后台运行, 即使你没有等待返回的 JoinHandle

派生一个任务 使该任务能够与其他任务并发执行。 派生的任务可以在当前线程上执行, 也可以被发送到其他线程执行。 具体细节取决于当前的 Runtime 配置。 在 正在运行的运行时中, 任务将立即在后台开始。 在阻塞的运行时中, 用户必须向前驱动运行时 (例如,通过调用 Runtime::block_on)。

可以保证 spawn 不会同步轮询正在派生的任务。 这意味着在持有锁的同时调用 spawn 不会带来与 派生任务死锁的风险。

无法保证派生的任务将执行到完成。 当运行时关闭时,所有未完成的任务都 将被丢弃,无论该任务的生命周期如何。

This function must be called from the context of a Tokio 运行时。 Tasks running on the Tokio runtime are always inside its context, but you can also enter the context using the Runtime::enter method.

§示例

在此示例中, 启动了一个服务器, 并使用 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
        });
    }
}

要并行运行多个任务并接收它们的结果, 可以将 join 句柄存储在一个 vector 中。

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

§Panics

Panics if called from outside of the Tokio 运行时。

§Using !Send values from a task

提供给 spawn 的任务 必须实现 Send。 但是, 只要它们仅存在于 对 .await 的调用之间, 就可以使用 !Send 值。

例如,下面的代码可以工作:

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();
}

.await 调用之间 保留一个 !Send 值 将导致一个不友好的编译错误消息, 类似于:

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

or:

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