Rust中spawn vs spawn_local

一开始只是想写spawn和spawn_local的区别,后来发现想要讲明白这个,需要先将一些之前的知识讲明白,于是有了这篇笔记。
spawn方法是指async_std::task::spawn方法或tokio::task::spawn方法,这两个类似
spawn_local方法是async_std::task::spawn_local方法,或tokio::task::spawn_local方法。
其中spawn_local在async_std包中需要开启 unstable feature,在tokio包中需要开启rt feature。

同步方法和异步方法的区别

同步方法是指:调用后立刻阻塞当前执行流程,必须等到方法内部逻辑完全执行完毕、返回结果,才继续往下执行后续代码。
异步方法是指:调用后不会阻塞当前执行流程,会立刻返回,让程序继续做其他事;等后台操作完成后,再通过 回调 /await/ 事件通知 回来执行后续逻辑。

相信上面的定义,大部分程序员都懂,也不会觉得有什么稀奇的,但是还是举个例子来详细说明下:

fn read_file_string_sync(){
    println!("starting read file");
    let file_content_res= std::fs::read_to_string("file_path");
    println!("end read file");
}
 void ReadFile()
 {
     Console.WriteLine("start read file");
     var a = File.ReadAllText("aaa");
     Console.WriteLine("end read file");
 }
async fn read_file_string_async(){
    println!("starting read file");
    let file_content_res= async_std::fs::read_to_string("file_path").await;
    println!("end read file");
}
async Task ReadFileAsync()
{
    Console.WriteLine("start read file");
    var a = await File.ReadAllTextAsync("aaa");
    Console.WriteLine("end read file");
}

例子很简单,就是读取一个文件的内容到字符串变量中,但是要详细解释下这两个方法在调用过程中的区别

同步代码

线程1(当前线程)打印 "starting read file"
线程1 调用同步文件读取方法(read_to_string / ReadAllText)
方法内部发起同步系统调用,请求磁盘IO
此时,线程1 被操作系统阻塞,进入休眠状态,不做任何其他工作
直到磁盘IO完成,数据准备就绪
操作系统唤醒线程1,将数据返回给方法
线程1 继续执行,打印 "end read file"

异步代码

线程1 打印 "starting read file"
线程1 调用异步文件读取方法(read_to_string_async / ReadAllTextAsync)
方法内部发起异步IO系统调用,请求磁盘读取数据
遇到 .await / await,当前任务立刻暂停,释放线程1
线程1 回到线程池,可以去处理其他任务(不再等待当前IO)

磁盘在后台完成读取,IO完成通知异步运行时
运行时从线程池取出任意一个空闲线程(可能是线程1,也可能是线程N)
将暂停的任务恢复执行
该线程继续打印 "end read file"

因此,这也是C#中强烈推荐使用异步方法的原因(我记得二零一几年的时候,那会全是同步的方法,后来微软几乎将所有的IO、网络等等推出了异步方法,并推荐使用异步的方法),会极大的提高线程的使用率。

spawn vs spawn_local

那这两个的区别是什么呢?
其实说到这里就很简单了,spawn就是await回来后,不一定是哪个线程接着执行;但spawn_local在await回来后,一定是之前的线程在接着执行。因此spawn_local方法接收的future不要求实现Send trait。
而且,C#中也有类似的实现。

posted @ 2026-05-06 22:05  伊森-w  阅读(20)  评论(0)    收藏  举报