假設我們有一些物件foo: Foo。有時,當我們需要對 進行多執行緒計算時foo,我們會克隆并移動它。但是,也有一些時候我們不需要克隆它,這可能很昂貴,而是可以把它放在一個Arc執行緒之間共享它的資料。在問題標題中,“共享”表示“在一個內部Arc”,而“隔離”表示僅在某些地方,即不在程式范圍內。
我可以想到兩種方法來做到這一點:
- 讓被呼叫者使用物件并在
Arc內部包裝/解包,將物件與元組中的任何其他資料一起回傳。 - 接受
Arc<Foo>為被呼叫者,將包裝/解包責任委托給呼叫者。
然而,這些似乎都不是特別干凈。(1) 具有復雜的回傳型別,這可能會使例如鏈式操作復雜化或阻礙,并且 (2) 強制呼叫者執行它不應該真正需要知道的作業。
我很好奇是否有處理這種情況的慣用模式。作為參考,我已經包含了上面描述的兩種模式的基本示例。
use std::sync::Arc;
use std::thread::{self, JoinHandle};
use std::time::Duration;
fn main() {
let foo = Foo(0);
// pattern 1
let (foo, _res) = process(foo);
// pattern 2
let foo = Arc::new(foo);
let _res = process2(Arc::clone(&foo));
let foo = Arc::try_unwrap(foo).unwrap();
}
#[derive(Debug)]
struct Foo(u8);
impl Clone for Foo {
/// an expensive clone operation that we want to avoid when possible
fn clone(&self) -> Self {
thread::sleep(Duration::from_secs(10));
Foo(self.0)
}
}
/// complicated return type
fn process(foo: Foo) -> (Foo, u8) {
let foo = Arc::new(foo);
let mut threads = Vec::<JoinHandle<()>>::new();
for _ in 1..=5 {
let f = Arc::clone(&foo);
let t = thread::spawn(move || {
println!("{:?}", f);
});
threads.push(t);
}
threads.into_iter().for_each(|t| t.join().unwrap());
(Arc::try_unwrap(foo).unwrap(), 1)
}
/// forces the caller to do work that should be hidden
fn process2(foo: Arc<Foo>) -> u8 {
let mut threads = Vec::<JoinHandle<()>>::new();
for _ in 1..=5 {
let f = Arc::clone(&foo);
let t = thread::spawn(move || {
println!("{:?}", f);
});
threads.push(t);
}
threads.into_iter().for_each(|t| t.join().unwrap());
1
}
操場
uj5u.com熱心網友回復:
這對于作用域執行緒(由crossbeam::scope或 的更高級別實用程式提供rayon)很有用,它允許您簡單地&Foo在執行緒內部使用 an 。這避免了需要將值移入和移出 a Arc。
此外,如果您使用,rayon您可以通過洗掉所有顯式執行緒創建并加入支持其并行迭代器來大大簡化代碼。
use rayon::iter::{ParallelIterator, IntoParallelIterator};
fn main() {
let foo = Foo(0);
let _res = process(&foo);
}
#[derive(Debug)]
struct Foo(u8);
fn process(foo: &Foo) -> u8 {
(1..=5).into_par_iter().for_each(|_i: usize| {
println!("{:?}", foo);
});
1
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/412301.html
標籤:
