我应该如何为并行计算生成线程?

今天,我进入了多线程。 由于这是一个新概念,我认为我可以通过将简单迭代转换为并行化迭代来开始学习。 但是,我想我在开始之前就陷入了困境。

最初,我的循环看起来像这样:

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毫秒才能完成这项工作。 我的实际目标是利用我的处理器并行运行线程并尽快完成工作。 这会变得复杂吗? 我该怎么做才能让这些线程并行运行,而不是并发?


我有一个四核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()
    }
}

如果你运行这个,你会看到“开始!” 打印500次,然后是500“Finished!”

显然,这里没有并行计算

不幸的是,你的问题没有充分说明你为什么要花时间。 在我提供的例子中,它需要少于600毫秒,所以它显然不会在串行中发生!


创建线程有成本。 如果线程内部的计算成本足够小,则线程成本或线程造成的效率低下将会使其变得更加糟糕。

例如,产生1000万个线程来翻倍1000万个u8s可能不值得。 向量化它可能会产生更好的性能。

也就是说,通过并行化廉价任务,您仍然可以获得一些改进。 但是你希望通过一个线程池使用更少的线程,这个线程池有少量的线程(所以你可以在任何给定的点上创建一个(很少的)线程数量,减少CPU争用)或者更复杂的东西(引擎盖下,api很简单)就像人造丝一样。

// Notice `.par_iter()` turns it into a `parallel iterator`
let stuff: Vec<u8> = items.par_iter().map(|item| {
    some_item_worker(&item)
}).collect();
链接地址: http://www.djcxy.com/p/35391.html

上一篇: How should I spawn threads for parallel computation?

下一篇: How does the getModifiers() method calculate the value for multiple modifiers?