并行执行外部命令并在 Rust 中捕获数组中的输出
Executing external commands in parallel and capturing the output in an array in Rust
我有以下 while 循环,它为 file_array
中的每个文件运行 generate_user_key
,并输出结果。我想将其并行化,以便返回生成的键的数组,并且该过程并行执行而不是顺序执行以使其更快。
use std::process::Command;
//file_array definition here
let mut i = 0;
while (i<100) {
let generated_key = Command::new("generate_user_key")
.arg(file_array[i])
.output()
.expect("generate_user_key command failed to start");
println!("stdout: {}", String::from_utf8_lossy(&generated_key.stdout));
i=i+1;
}
在 Rust 中实现它的最佳方法是什么?
当所有其他方法都失败时,抛出线程来解决问题。这几乎肯定不是正确的方法,但它确实有效。
let mut join_handles = Vec::new();
for _ in 0..100 {
join_handles.push(thread::spawn(|| {
let generated_key = Command::new("generate_user_key")
.arg(file_array[i])
.output()
.expect("generate_user_key command failed to start");
String::from_utf8_lossy(&generated_key.stdout)
}));
}
let outputs = join_handles.into_iter().map(Result::unwrap).collect::<Vec<_>>();
编辑: 正确的解决方案可能是使用 Command::spawn
来启动进程而不阻塞。 OS 然后可以并行处理 运行 它们,然后您可以收集输出。
如果您想使用 rayon
then you can simply create into_par_iter
遍历数组项并处理数组项
use std::process::Command;
use rayon::iter::{ParallelIterator, IntoParallelIterator};
fn main() {
let arr = [1, 2, 3, 4, 5];
let result: Vec<_> = arr.into_par_iter().flat_map(|value| {
let output = Command::new("sh")
.args(["-c", &format!("echo {}", value)])
.output()
.expect("failed to execute process");
println!("Index: {}, Output: {:?}", value, output.stdout);
output.stdout
});
println!("{:?}", result);
}
你也可以使用range
来循环使用counter
作为array
索引
use std::process::Command;
use rayon::iter::{ParallelIterator, IntoParallelIterator};
fn main() {
let arr = [1, 2, 3, 4, 5];
let result: Vec<_> = (0..arr.len()).into_par_iter().flat_map(|idx| {
let output = Command::new("sh")
.args(["-c", &format!("echo {}", arr[idx])])
.output()
.expect("failed to execute process");
println!("Index: {}, Output: {:?}", idx, output.stdout);
output.stdout
});
println!("{:?}", result);
}
示例使用 thread
use std::thread;
use std::time::Duration;
fn main() {
let mut threads = vec![];
for idx in 0..arr.len() {
threads.push(thread::spawn(move || -> Vec<_> {
let output = Command::new("sh")
.args(["-c", &format!("echo -n {}", idx)])
.output()
.expect("failed to execute process");
println!("Index: {}, Output: {:?}", idx, output.stdout);
thread::sleep(Duration::from_millis(1));
output.stdout
}));
}
let result = threads.into_iter().flat_map(|c| c.join().unwrap()).collect::<Vec<_>>();
println!("{:?}", result);
}
rayon 这应该很容易做到。例如。像这样的东西(未经测试,因为我没有你的generate_user_key
):
use rayon::prelude::*;
let keys = (0..100).into_par_iter().map (|_| {
Command::new("generate_user_key")
.arg(file_array[i])
.output()
.expect("generate_user_key command failed to start")
.stdout
})
.collect::<Vec<_>>();
或更好:
use rayon::prelude::*;
let keys = file_array.par_iter().map (|f| {
Command::new("generate_user_key")
.arg(f)
.output()
.expect("generate_user_key command failed to start")
.stdout
})
.collect::<Vec<_>>();