多线程
前端同学对于WebWorker肯定比较熟悉,对于计算量大的业务,我们可以将计算逻辑分配到多个线程去处理,减少主线程的压力,提高处理速度,在rust中启用多线程很方便,如果用JS的话来说,启动一个线程就像传递一个回调函数一样简单
使用 spawn 创建新线程
使用标准库中的thread模块创建一个spawn子线程:
1 | rust复制代码use std::thread; // 引入thread |
当主线程结束时,spawn线程也会结束,而不管其是否执行完毕,上面spawn线程并没有执行完成。
使用 join 等待所有线程结束
我们可以使用thread::spawn返回值的join方法控制让main线程去等待spawn线程的执行完成:
1 | rust复制代码// 获取spawn线程管理工具 |
join会阻塞当前线程直到handle线程结束,阻塞(Blocking)线程意味着阻止该线程执行工作或退出。
如果将handle.join()移动到for循环之前呢?可以猜一下是怎么输出的:
1 | rust复制代码// 略... |
输出结果:
1 | rust复制代码// spawn: 1 |
可以看到spawn线程的循环会先执行完成,再执行主线程的循环。
线程与 move 闭包
上面的spawn线程中的代码对main线程中的数据没有引用,当spawn线程使用main线程中的数据时:
1 | rust复制代码let n = vec![1,2,3]; |
上边闭包尝试借用 v。然而这有一个问题:rust 不知道这个新建线程会执行多久,所以无法知晓 v 的引用是否一直有效,例如:
1 | rust复制代码let n = vec![1,2,3]; |
因为当线程中对n有借用,在线程还没执行的时候,后边的drop已经将n丢弃了。
我们可以通过在闭包之前增加 move 关键字,强制闭包获取其使用的n的所有权:
1 | rust复制代码let n = vec![1, 2, 3]; |
上面代码中,将n的所有权移动到了spawn闭包中,所以能够正常执行。
如果仍然使用drop的话:
1 | rust复制代码let n = vec![1, 2, 3]; |
因为n已经被移动到了spawn闭包中,所以不能在后面以任何方式继续使用,即使println!(“{:?}”,n),也是不允许的。
本文转载自: 掘金