pub fn spawn<F>(future: F) -> JoinHandle<F::Output> ⓘ展开描述
生成一个新的异步任务,并为其返回一个 JoinHandle。
调用 spawn 时,所提供的 future 将立即开始在后台运行,即使你没有 await 返回的 JoinHandle。
生成任务使该任务能够与其他任务并发执行。生成的任务可能在当前线程上执行,也可能被发送到另一个线程执行。具体细节取决于当前的 Runtime 配置。在正在运行的运行时中,任务将立即在后台启动。在阻塞的运行时上,用户必须推动运行时向前(例如,通过调用 Runtime::block_on)。
保证 spawn 不会同步轮询正在生成的任务。这意味着在持有锁时调用 spawn 不会与生成的任务产生死锁风险。
不能保证生成的任务一定会执行到完成。关闭运行时时,所有未完成的任务都将被 drop,无论该任务的生命周期如何。
此函数必须从 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
});
}
}要并行运行多个任务并接收它们的结果,可以将 join handle 存储在向量中。
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 运行时的外部调用,则会发生 panic。
§Using !Send values from a task
提供给 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();
}在跨 .await 调用之间持有 !Send 值将导致类似于以下的、不友好的编译错误消息:
`[... some type ...]` cannot be sent between threads safely或:
error[E0391]: cycle detected when processing `main`