tokio::spawn
原型
pub fn spawn<T>(task: T) -> JoinHandle<T::Output>
where
T: Future + Send + 'static,
T::Output: Send + 'static,
spawn派生一个异步任务,并返回一个JoinHandle,用于与异步任务交互。如调用await获取返回值。
派生任务使该任务能够与其他任务并发执行。派生的任务可以在当前线程上执行,也可以发送到另一个线程执行。具体内容取决于当前的运行时配置。
不能保证派生的任务将执行到完成。当运行时关闭时,无论该任务的生命周期如何,所有未完成的任务都将被丢弃。
例子
#[tokio::main]
async fn main() {
let handle = tokio::spawn(async {
// Do some async work
"return value"
});
// Do some other work
println!("Do some other work");
let out = handle.await.unwrap();
println!("GOT {}", out);
}
并行和协程
并行编程:每次启动新线程处理任务。
协程编程:tokio提供的是协程编程。tokio::spawn() 并不是启动一个新的线程,只是使用 Tokio 所建立的线程池,Tokio 会管理调度这些被启动的任务,而不需要程序员的参与。在标准库的基础上,Tokio 也提供了一些并行常用的同步工具,比如信号量(Semaphore)。
相同点:
协程和并行都是通过同时执行多个任务来提高性能
不同点:
本质不同。协程是在由于 IO 造成等待时去执行其他计算任务来提高系统资源的利用率,而并行只是挖掘硬件本身所提供的额外计算资源,并不处理 IO 等待的时间浪费。
'static
派生任务的生命周期必须是’static。
也就是说任务中不能引用任何外部数据。
下面编译失败,派生任务引用了v。
use tokio::task;
#[tokio::main]
async fn main() {
let v = vec![1, 2, 3];
task::spawn(async {
println!("Here's a vec: {:?}", v);
});
}
move
通过move,可将外部变量移动到任务中。如果需要从多个任务同时访问单个数据,则必须使用Arc等同步原语来共享该数据。
例子
use tokio::task;
#[tokio::main]
async fn main() {
let v = vec![1, 2, 3];
task::spawn(async move {
println!("Here's a vec: {:?}", v);
}).await;
}
Send
派生任务需要实现send方法。
这将使Tokio运行时在线程之间移动任务,而这些任务在.aWait挂起。