程序仍然在使用 par_iter 和 par_extend 的一个线程上运行
Program still runs on one thread using par_iter and par_extend
我正在尝试并行化我的一部分代码,尽管它使用 rayon
和并行迭代器 par_iter()
和 par_extend()
,但它看起来仍然运行在单线程。
我只是创建了一个 i32
向量,用很多值填充它,然后将这些值移动到 collections::HashSet
整数中。
我的单线程代码:
use std::collections::HashSet;
fn main() {
let my_vec: Vec<i64> = (0..100_000_000).collect();
let mut my_set: HashSet<i64> = HashSet::new();
let st = std::time::Instant::now();
my_set.extend(
my_vec.iter().map(|x| x*(x+3)/77+44741) // this is supposed to take a while to compute
);
let dur = st.elapsed();
println!("{:?}", dur);
}
运行 时间平均在 8.86 s
左右。
下面是使用并行迭代器的代码:
extern crate rayon;
use rayon::prelude::*;
use std::collections::HashSet;
fn main() {
let my_vec: Vec<i64> = (0..100_000_000).collect();
let mut my_set: HashSet<i64> = HashSet::new();
let st = std::time::Instant::now();
my_set.par_extend(
my_vec.par_iter().map(|x| x*(x+3)/77+44741) // this is supposed to take a while to compute
);
let dur = st.elapsed();
println!("{:?}", dur);
}
'parallel'版本的平均运行时间几乎相同(8.62 s
),cpu监视器清楚地显示单个cpu 正在 100% 工作,而其他人只是等待。
你知道我哪里做错了,或者没看懂吗?
你的模拟是不正确的,因为你的计算实际上很快,快到比线程上下文切换快几个数量级。您的核心处于 100% 可能是人造丝运行时,而其他核心正在等待它。
如果你真的用睡眠代替你的计算,结果如你所料:
use std::collections::HashSet;
use rayon::prelude::*; // 1.1.0
use std::time::Duration;
fn main() {
fn slow(i: &i64) -> i64 {
std::thread::sleep(Duration::from_millis(5));
*i
}
let my_vec: Vec<i64> = (0..100).collect();
let mut my_set: HashSet<i64> = HashSet::new();
let st = std::time::Instant::now();
my_set.extend(
my_vec.iter().map(slow) // this is supposed to take a while to compute
);
let dur = st.elapsed();
println!("Regular: {:?}", dur);
let st = std::time::Instant::now();
my_set.par_extend(
my_vec.par_iter().map(slow) // this is supposed to take a while to compute
);
let dur = st.elapsed();
println!("Rayon: {:?}", dur);
}
输出:
Regular: 685.670791ms
Rayon: 316.733253ms
当您尝试优化您的代码时,您必须仔细地对其进行基准测试,因为有时,当您并行化您的代码时,这会使它变慢。
我正在尝试并行化我的一部分代码,尽管它使用 rayon
和并行迭代器 par_iter()
和 par_extend()
,但它看起来仍然运行在单线程。
我只是创建了一个 i32
向量,用很多值填充它,然后将这些值移动到 collections::HashSet
整数中。
我的单线程代码:
use std::collections::HashSet;
fn main() {
let my_vec: Vec<i64> = (0..100_000_000).collect();
let mut my_set: HashSet<i64> = HashSet::new();
let st = std::time::Instant::now();
my_set.extend(
my_vec.iter().map(|x| x*(x+3)/77+44741) // this is supposed to take a while to compute
);
let dur = st.elapsed();
println!("{:?}", dur);
}
运行 时间平均在 8.86 s
左右。
下面是使用并行迭代器的代码:
extern crate rayon;
use rayon::prelude::*;
use std::collections::HashSet;
fn main() {
let my_vec: Vec<i64> = (0..100_000_000).collect();
let mut my_set: HashSet<i64> = HashSet::new();
let st = std::time::Instant::now();
my_set.par_extend(
my_vec.par_iter().map(|x| x*(x+3)/77+44741) // this is supposed to take a while to compute
);
let dur = st.elapsed();
println!("{:?}", dur);
}
'parallel'版本的平均运行时间几乎相同(8.62 s
),cpu监视器清楚地显示单个cpu 正在 100% 工作,而其他人只是等待。
你知道我哪里做错了,或者没看懂吗?
你的模拟是不正确的,因为你的计算实际上很快,快到比线程上下文切换快几个数量级。您的核心处于 100% 可能是人造丝运行时,而其他核心正在等待它。
如果你真的用睡眠代替你的计算,结果如你所料:
use std::collections::HashSet;
use rayon::prelude::*; // 1.1.0
use std::time::Duration;
fn main() {
fn slow(i: &i64) -> i64 {
std::thread::sleep(Duration::from_millis(5));
*i
}
let my_vec: Vec<i64> = (0..100).collect();
let mut my_set: HashSet<i64> = HashSet::new();
let st = std::time::Instant::now();
my_set.extend(
my_vec.iter().map(slow) // this is supposed to take a while to compute
);
let dur = st.elapsed();
println!("Regular: {:?}", dur);
let st = std::time::Instant::now();
my_set.par_extend(
my_vec.par_iter().map(slow) // this is supposed to take a while to compute
);
let dur = st.elapsed();
println!("Rayon: {:?}", dur);
}
输出:
Regular: 685.670791ms
Rayon: 316.733253ms
当您尝试优化您的代码时,您必须仔细地对其进行基准测试,因为有时,当您并行化您的代码时,这会使它变慢。