Qqw*_*qwy 15 multithreading closures lifetime move-semantics rust
我有一个通用struct
设置和一个额外的变量设置,我想调整和使用。
对于整数范围内的所有可能值,我想启动一个(作用域)线程,并将此变量设置为该值。根据这个值,它们做的工作略有不同。
这些线程中的每一个都应该能够读取常规设置结构。
use crossbeam; // 0.7.3
struct Settings {
// ... many fields
}
const MAX_FEASIBLE_SCORE: u8 = 10;
fn example(settings: Settings) {
crossbeam::scope(|scope| {
for score in 0..MAX_FEASIBLE_SCORE {
scope.spawn(|_| {
let work_result = do_cool_computation(&settings, score);
println!("{:?}", work_result);
});
}
})
.unwrap();
}
fn do_cool_computation(_: &Settings, _: u8) {}
Run Code Online (Sandbox Code Playgroud)
这不编译:
use crossbeam; // 0.7.3
struct Settings {
// ... many fields
}
const MAX_FEASIBLE_SCORE: u8 = 10;
fn example(settings: Settings) {
crossbeam::scope(|scope| {
for score in 0..MAX_FEASIBLE_SCORE {
scope.spawn(|_| {
let work_result = do_cool_computation(&settings, score);
println!("{:?}", work_result);
});
}
})
.unwrap();
}
fn do_cool_computation(_: &Settings, _: u8) {}
Run Code Online (Sandbox Code Playgroud)
这将无效,&settings
因为第一次循环迭代将settings
在move
闭包中取得所有权。
使其工作的唯一简单方法是:
Settings
结构复制到每个线程中(这在我的实际应用程序中相当昂贵)Arc
around settings
,也感觉有点可惜。有没有办法在这里绕过引用计数?有没有办法可以score
在仍然允许引用的同时进入内部闭包settings
?
Qqw*_*qwy 11
是的,可以只将一个或一些变量移动到闭包中(而不是全部或全部)。
是的,这可以用来“规避”引用计数。
我在文档中找到了一个答案rayon::scope
,结果证明正是关于这个问题:“访问堆栈数据[从范围内的线程范围内]”。该页面还有一个比这个问题中的伪代码更清晰的示例。
事实证明,您可以:
使用move
闭包,但通过用引用遮蔽变量来引用外部作用域中的变量,因此通过引用而不是值来捕获它们,使用let settings = &settings
:
crossbeam::scope(|scope| {
let settings = &settings; // refer to outer variable by reference
for score in 0..MAX_FEASIBLE_SCORE {
scope.spawn(move |_| {
let work_result = do_cool_computation(settings, score);
println!("{:?}", work_result);
});
}
})
.unwrap();
Run Code Online (Sandbox Code Playgroud)使用正常的闭包,并且只通过使用let score = score
以下命令在闭包内隐藏它们来移动所需的变量:
crossbeam::scope(|scope| {
for score in 0..MAX_FEASIBLE_SCORE {
scope.spawn(|_| {
let score = score; // capture only score
let work_result = do_cool_computation(&settings, score);
println!("{:?}", work_result);
});
}
})
.unwrap();
Run Code Online (Sandbox Code Playgroud)倒闭!闭包箱中的宏能够选择性地引用、移动或克隆变量到闭包中。
取自文档的示例:
use closure::closure;
let string = "move".to_string();
let x = 10;
let mut y = 20;
let rc = Rc::new(5);
let closure = closure!(move string, ref x, ref mut y, clone rc, |arg: i32| {
...
});
Run Code Online (Sandbox Code Playgroud)
捕获但未列出的变量默认会被移动。