我一直在Rust中做多线程功能。我正在尝试翻译我在Go中编写的代码,该代码在迭代时更新映射的值,并创建一个新线程。(简化代码(
my_map := make(map[string]string)
var wg sync.WaitGroup
wg.Add(len(my_map ))
for key := range my_map {
go func(key string) {
defer wg.Done()
stdout, _ := exec.Command(key, "some command").Output()
lock.Lock()
defer lock.Unlock()
my_map[key] = "updating map value while iterating" // eg stdout
}(key)
}
到目前为止,我试过像这个
let mut my_map = HashMap::new();
...
for (key, value) in my_map.iter_mut() {
// Should update map value, tried with crossbeam_utils:thread;
thread::scope(|s| {
s.spawn(|_| {
let cmd = format!("some command {key}"); // will borrow key
let cmd: Vec<&str> = cmd.as_str().split(" ").map(|s| s).collect();
let proc = Popen::create(
&cmd,
PopenConfig {
stdout: Redirection::Pipe,
stdin: Redirection::None,
stderr: Redirection::None,
..Default::default()
},
);
let mut proc = proc.expect("Failed to create process.");
let (out, _) = proc.communicate(None).unwrap();
let stdout = out.unwrap();
*value = "I will update value with something new";
});
})
.unwrap();
}
我创建了一个类似于等待组的处理程序向量,并将每个线程推送到那里。然后,我迭代每个句柄并.unwrap()
它,以确保它完成。
let mut handles: Vec<std::thread::JoinHandle<()>> = Vec::new();
for (key, value) in my_map.iter_mut() {
handles.push(thread::spawn(move || {
let cmd = format!("some command");
let cmd: Vec<&str> = cmd.as_str().split(" ").map(|s| s).collect();
let proc = Popen::create(
&cmd,
PopenConfig {
stdout: Redirection::Pipe,
stdin: Redirection::None,
stderr: Redirection::None,
..Default::default()
},
);
let mut proc = match proc {
Ok(proc) => proc,
Err(e) => {
panic!("Failed to create process: {:?}", e)
}
};
let (out, _) = proc.communicate(None).unwrap();
let stdout = out.unwrap();
*value = "I will update value with something new";
}));
}
for handle in handles {
handle.join().unwrap(); // This won't block other threads, but it will make sure it can unwrap every thread before it continues. In other words, this only runs as long as your longest running thread.
}