是否可以在不进行任何克隆的情况下与线程共享数据?
Is it possible to share data with threads without any cloning?
当我将工作委派给线程时,我经常有一段数据会比所有线程都存活,例如以下示例中的 numbers
:
use std::thread;
fn main() {
let numbers = vec![1, 2, 3];
let thread_a = thread::spawn(|| println!("{}", numbers.len()));
let thread_b = thread::spawn(|| println!("{}", numbers.len()));
thread_a.join().unwrap();
thread_b.join().unwrap();
}
它在任何地方都没有被修改,并且由于 join
s,它保证线程完成使用它。然而,Rust 的借用检查器无法分辨:
error[E0373]: closure may outlive the current function, but it borrows `numbers`, which is owned by the current function
--> src/main.rs:6:34
|
6 | let thread_a = thread::spawn(|| println!("{}", numbers.len()));
| ^^ ------- `numbers` is borrowed here
| |
| may outlive borrowed value `numbers`
|
note: function requires argument type to outlive `'static`
--> src/main.rs:6:20
|
6 | let thread_a = thread::spawn(|| println!("{}", numbers.len()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `numbers` (and any other referenced variables), use the `move` keyword
|
6 | let thread_a = thread::spawn(move || println!("{}", numbers.len()));
| ^^^^^^^
到目前为止我看到的解决方案都涉及克隆数据(或克隆 Arc
数据)。但是,是否可以在不进行任何克隆的情况下做到这一点?
您可能有错误的想法:克隆一个 Arc
只是递增一个引用计数器并复制一个指针;它不执行任何额外的分配。当然,创建 Arc
涉及分配,但是,您已经在分配以构建 Vec
,因此额外的固定大小分配不太可能造成伤害。
如果您真正需要的只是长度,您可以计算在线程闭包之外并将其存储在变量中; a usize
跨越线程边界没有问题。
问题是编译器无法从 join()
的使用中推断出给定线程的生命周期有限...它甚至都不会尝试。
在 Rust 1.0 之前,是 一个 thread::scoped
构造函数,它允许您传入非 'static
引用,但必须取消 -由于内存安全问题而稳定。请参阅 How can I pass a reference to a stack variable to a thread? 了解替代方案。
当我将工作委派给线程时,我经常有一段数据会比所有线程都存活,例如以下示例中的 numbers
:
use std::thread;
fn main() {
let numbers = vec![1, 2, 3];
let thread_a = thread::spawn(|| println!("{}", numbers.len()));
let thread_b = thread::spawn(|| println!("{}", numbers.len()));
thread_a.join().unwrap();
thread_b.join().unwrap();
}
它在任何地方都没有被修改,并且由于 join
s,它保证线程完成使用它。然而,Rust 的借用检查器无法分辨:
error[E0373]: closure may outlive the current function, but it borrows `numbers`, which is owned by the current function
--> src/main.rs:6:34
|
6 | let thread_a = thread::spawn(|| println!("{}", numbers.len()));
| ^^ ------- `numbers` is borrowed here
| |
| may outlive borrowed value `numbers`
|
note: function requires argument type to outlive `'static`
--> src/main.rs:6:20
|
6 | let thread_a = thread::spawn(|| println!("{}", numbers.len()));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: to force the closure to take ownership of `numbers` (and any other referenced variables), use the `move` keyword
|
6 | let thread_a = thread::spawn(move || println!("{}", numbers.len()));
| ^^^^^^^
到目前为止我看到的解决方案都涉及克隆数据(或克隆 Arc
数据)。但是,是否可以在不进行任何克隆的情况下做到这一点?
您可能有错误的想法:克隆一个 Arc
只是递增一个引用计数器并复制一个指针;它不执行任何额外的分配。当然,创建 Arc
涉及分配,但是,您已经在分配以构建 Vec
,因此额外的固定大小分配不太可能造成伤害。
如果您真正需要的只是长度,您可以计算在线程闭包之外并将其存储在变量中; a usize
跨越线程边界没有问题。
问题是编译器无法从 join()
的使用中推断出给定线程的生命周期有限...它甚至都不会尝试。
在 Rust 1.0 之前,是 一个 thread::scoped
构造函数,它允许您传入非 'static
引用,但必须取消 -由于内存安全问题而稳定。请参阅 How can I pass a reference to a stack variable to a thread? 了解替代方案。