今天,我进入了多线程。由于这是一个新概念,我认为我可以通过将简单的迭代转换为并行化的来开始学习。但是,我认为在我开始之前就陷入了困境。
最初,我的循环看起来像这样:
let stuff: Vec<u8> = items.into_iter().map(|item| {
some_item_worker(&item)
}).collect();
我把相当多的东西放到了items
中,完成计算花了大约0.05秒。所以,一旦我成功实现了多线程,我很高兴看到时间减少了!
当我使用线程时,我遇到了麻烦,可能是由于我的错误推理。
use std::thread;
let threads: Vec<_> = items.into_iter().map(|item| {
thread::spawn(move || {
some_item_worker(&item)
})
}).collect(); // yeah, this is followed by another iter() that unwraps the values
我有一个四核CPU,这意味着我最多只能同时运行4个线程。我猜它是这样工作的:一旦迭代器启动,线程就会产生。每当线程结束时,另一个线程开始,这样在任何给定时间,4个线程同时运行。
结果是(经过一些重新运行)〜0.2秒完成相同的计算。显然,这里没有并行计算。我不知道为什么时间增加了4倍,但我确信我误会了什么。
由于这不是正确的方法,我应该如何修改程序以便线程并发执行?
对不起,我错了~0.2秒。当我注意到通常的迭代运行2秒时,我醒来并再次尝试。事实证明,某些过程一直在大量消耗内存。当我重新启动系统并再次尝试线程迭代时,它运行了大约0.07秒。以下是每次运行的时间安排。
实际迭代(第一个):
0.0553760528564 seconds
0.0539519786835 seconds
0.0564560890198 seconds
螺纹一个:
0.0734670162201 seconds
0.0727820396423 seconds
0.0719120502472 seconds
我同意线程确实同时运行,但它似乎消耗了另外20毫秒来完成这项工作。我的实际目标是利用我的处理器并行运行线程并尽快完成工作。这会复杂吗?我该怎么做才能使这些线程并行运行,而不是并发?
答案 0 :(得分:2)
我有一个四核CPU,这意味着我最多只能同时运行4个线程。
只有4个可以同时运行,但你当然可以创建超过4个......
每当一个线程结束时,另一个线程开始,这样在任何给定的时间,4个线程同时运行(这只是猜测)。
每当你有一个猜测时,你应该创建一个实验来判断你的猜测是否正确。这是一个:
use std::{iter, thread, time::Duration};
fn main() {
let items: Vec<_> = iter::repeat(0).take(500).collect();
let threads: Vec<_> = items
.into_iter()
.map(|_| {
thread::spawn(move || {
println!("Started!");
thread::sleep(Duration::from_millis(500));
println!("Finished!");
})
})
.collect();
for handle in threads {
handle.join().unwrap()
}
}
如果你运行它,你会看到&#34;开始!&#34;打印出500次,然后是500&#34;完成!&#34;
显然,这里没有并行计算
不幸的是,您的问题并没有充实,我们无法告诉您为什么您的时间过去了。在我提供的示例中,它需要不到600毫秒,所以它显然没有串行发生!
答案 1 :(得分:0)
创建一个线程需要付出代价。如果线程内的计算成本足够小,那么线程的成本或线程导致的低效率就会相形见绌。
例如,产生1000万个线程以使1000万u8s翻倍可能不值得。对它进行矢量化可能会产生更好的性能。
也就是说,通过并行化廉价任务,您仍然可以获得一些改进。但是你希望通过一个线程池使用更少的线程w /少量的线程(所以你在任何给定点创建(小)线程数,减少CPU争用)或更复杂的东西(在引擎盖下,api很简单)就像Rayon。
// Notice `.par_iter()` turns it into a `parallel iterator`
let stuff: Vec<u8> = items.par_iter().map(|item| {
some_item_worker(&item)
}).collect();