gpt4 book ai didi

multithreading - 有没有办法让 Rust 闭包只将一些变量移入其中?

转载 作者:行者123 更新时间:2023-11-29 07:58:27 38 4
gpt4 key购买 nike

我有一个通用的 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) {}

这不编译:

error[E0373]: closure may outlive the current function, but it borrows `score`, which is owned by the current function
--> src/lib.rs:12:25
|
10 | crossbeam::scope(|scope| {
| ----- has type `&crossbeam_utils::thread::Scope<'1>`
11 | for score in 0..MAX_FEASIBLE_SCORE {
12 | scope.spawn(|_| {
| ^^^ may outlive borrowed value `score`
13 | let work_result = do_cool_computation(&settings, score);
| ----- `score` is borrowed here
|
note: function requires argument type to outlive `'1`
--> src/lib.rs:12:13
|
12 | / scope.spawn(|_| {
13 | | let work_result = do_cool_computation(&settings, score);
14 | | println!("{:?}", work_result);
15 | | });
| |______________^
help: to force the closure to take ownership of `score` (and any other referenced variables), use the `move` keyword
|
12 | scope.spawn(move |_| {
| ^^^^^^^^

这将使 &settings 无效,因为第一个循环迭代将在 move 闭包中获取 settings 的所有权。

让它工作的唯一简单方法是:

  • Settings 结构复制到每个线程中(这在我的实际应用程序中相当昂贵)
  • settings 周围引入了一个Arc,这也感觉有点不幸。

有什么办法可以绕过引用计数吗?有没有一种方法可以将 score move 到内部闭包中,同时仍允许引用 settings

最佳答案

是的,可以只将一个或一些变量 move 到闭包中(而不是全部或不 move )。

是的,这可以用来“规避”引用计数。

我在 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();
```

Playground所以在这里,我们 move 了'all used variables'但是预先把settings变成了一个引用,所以它被借用了。 (迂腐地:我们“move 引用”,但这正是“借用”的意思。)

还有第二种可能:借用所有变量(不 move 任何东西)。

这种可能性适用于许多情况,但不适用于此处。 (因为在这里,我们必须按值捕获 score,因为在 for 循环的下一次迭代和传递给 scope.spawn 的闭包期间,它不会存在 会比这个长寿)。

摘自 rayon::scope 的文档

use rayon;

fn main() {
let ok: Vec<i32> = vec![1, 2, 3];
rayon::scope(|s| {
let bad: Vec<i32> = vec![4, 5, 6];
s.spawn(|_| {
// Transfer ownership of `bad` into a local variable (also named `bad`).
// This will force the closure to take ownership of `bad` from the environment.
let bad = bad;
println!("ok: {:?}", ok); // `ok` is only borrowed.
println!("bad: {:?}", bad); // refers to our local variable, above.
});

s.spawn(|_| println!("ok: {:?}", ok)); // we too can borrow `ok`
});
}

Playground

关于multithreading - 有没有办法让 Rust 闭包只将一些变量移入其中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58459643/

38 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com