编程语言有一些不同的方法来实现线程,而且很多操作系统提供了创建新线程的 API 。Rust 标准库使用 1:1 线程实现 , 这代表程序的每一个语言级线程使用一个系统线程 。1. Rust线程实现理念在大部分现代操作系统中,已执行程序的代码在一个 进程(process)中运行 , 操作系统则会负责管理多个进程 。在程序内部 , 也可以拥有多个同时运行的独立部分 。这些运行这些独立部分的功能被称为 线程(threads) 。例如,web 服务器可以有多个线程以便可以同时响应多个请求 。
文章插图
将程序中的计算拆分进多个线程可以改善性能 , 因为程序可以同时进行多个任务,不过这也会增加复杂性 。因为线程是同时运行的,所以无法预先保证不同线程中的代码的执行顺序 。这会导致诸如此类的问题:
- 竞态条件(Race conditions),多个线程以不一致的顺序访问数据或资源 。
- 死锁(Deadlocks) , 两个线程相互等待对方,这会阻止两者继续运行 。
- 只会发生在特定情况且难以稳定重现和修复的 bug 。
编程语言有一些不同的方法来实现线程,而且很多操作系统提供了创建新线程的 API 。Rust 标准库使用 1:1 线程实现,这代表程序的每一个语言级线程使用一个系统线程 。
2.使用spawn创建新线程为了创建一个新线程,需要调用 thread::spawn 函数并传递一个闭包, 并在其中包含希望在新线程运行的代码 。看下面的例子:
use std::thread;use std::time::Duration;fn mAIn() {thread::spawn(|| {for i in 1..10 {println!("hi number {} from the spawned thread!", i);thread::sleep(Duration::from_millis(1));}});for i in 1..5 {println!("hi number {} from the main thread!", i);thread::sleep(Duration::from_millis(1));}}
注意当 Rust 程序的主线程结束时 , 新线程也会结束 , 而不管其是否执行完毕 。这个程序的输出可能每次都略有不同,不过它大体上看起来像这样:文章插图
thread::sleep 调用强制线程停止执行一小段时间,这会允许其他不同的线程运行 。这些线程可能会轮流运行,不过并不保证如此:这依赖操作系统如何调度线程 。在这里,主线程首先打印 , 即便新创建线程的打印语句位于程序的开头,甚至即便我们告诉新建的线程打印直到 i 等于 9,它在主线程结束之前也只打印到了 5 。
如果运行代码只看到了主线程的输出,或没有出现重叠打印的现象,尝试增大区间 (变量 i 的范围) 来增加操作系统切换线程的机会 。
3.使用join等待所有线程结束由于主线程结束,上面演示的代码大部分时候不光会提早结束新建线程,因为无法保证线程运行的顺序 , 甚至不能实际保证新建线程会被执行!
可以通过将 thread::spawn 的返回值储存在变量中来修复新建线程部分没有执行或者完全没有执行的问题 。thread::spawn 的返回值类型是 JoinHandle 。JoinHandle 是一个拥有所有权的值 , 当对其调用 join 方法时 , 它会等待其线程结束 。
看下面的示例代码:
use std::thread;use std::time::Duration;fn main() {let handle = thread::spawn(|| {for i in 1..10 {println!("hi number {} from the spawned thread!", i);thread::sleep(Duration::from_millis(1));}});for i in 1..5 {println!("hi number {} from the main thread!", i);thread::sleep(Duration::from_millis(1));}handle.join().unwrap();}
通过调用 handle 的 join 会阻塞当前线程直到 handle 所代表的线程结束 。阻塞(Blocking)线程意味着阻止该线程执行工作或退出 。因为我们将 join 调用放在了主线程的 for 循环之后,编译这段代码后运行结果如下:文章插图
这两个线程仍然会交替执行,不过主线程会由于 handle.join() 调用会等待直到新建线程执行完毕 。
不过如果将 handle.join() 移动到 main 中 for 循环之前会发生什么呢,看下面的代码:
use std::thread;use std::time::Duration;fn main() {let handle = thread::spawn(|| {for i in 1..10 {println!("hi number {} from the spawned thread!", i);thread::sleep(Duration::from_millis(1));}});handle.join().unwrap();for i in 1..5 {println!("hi number {} from the main thread!", i);thread::sleep(Duration::from_millis(1));}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 只有了解关键词排名机制,才可以避免走入网站优化深渊
- 秀米该咋滴才可以上传视频,如何在秀米编辑器中上传图片
- 在哪里开失业证明?
- 男性器官衰老顺序已公开,建议对照一下,看看自己在哪个阶段?
- 医用酒精喷在食物上 医用酒精喷到食物上还可以吃吗
- 猫在楼道里丢了怎么找,猫咪丢了怎么快速找回
- 披着军旅外衣的6部烂剧,每部都在侮辱观众智商
- 端午扫帚挂件应该挂在哪里 端午节扫帚挂哪里
- 白素贞为什么怕端午节 白素贞在端午节那天喝了什么
- 多肉砍头后怎么处理