【问题标题】:Calculate prefix product with std::exclusive_scan and execution policy std::execution::par使用 std::exclusive_scan 和执行策略 std::execution::par 计算前缀乘积
【发布时间】:2021-07-23 04:20:28
【问题描述】:

我正在用std::exclusive_scan 计算prefix product

#include <algorithm>/
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> input{1,2,3,4,5,6,7,8,9};
    std::exclusive_scan(std::begin(input), std::end(input),
                        std::begin(input),
                        1, std::multiplies<> {});

    std::cout << "exclusive_scan: "
    for (auto const product : input) {
        std::cout << product << " ";
    }
    std::cout << '\n';
    return 0;
}

输出如预期exclusive_scan: 1 1 2 6 24 120 720 5040 40320

现在我想将它与std::execution::par 并行化并更改代码:

#include <algorithm>
#include <execution>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> input{1,2,3,4,5,6,7,8,9};
    std::exclusive_scan(std::execution::par,
                        std::begin(input), std::end(input),
                        std::begin(input),
                        1, std::multiplies<> {});

    std::cout << "exclusive_scan: "
    for (auto const product : input) {
        std::cout << product << " ";
    }
    std::cout << '\n';
    return 0;
}

但现在输出是exclusive_scan: 1 1 1 1 1 1 1 1 1

我正在使用 gcc 10.2.0 并链接到 -ltbb

为什么我不能将std::exclusive_scanstd::execution::par 一起使用?
我的实现方式有问题吗?
需要进行哪些更改?

【问题讨论】:

标签: c++ stl c++17 tbb


【解决方案1】:

当您将exclusive_scan 与默认执行策略一起使用时,如:

exclusive_scan(input.begin(), input.end(), output.begin(), initial_value, operate)

会发生什么:

initial_value_temp = operate(input[0], initial_value);
output[0] = initial_value;
initial_value = initial_value_temp

initial_value_temp = operate(input[1], initial_value);
output[1] = initial_value;
initial_value = initial_value_temp

     ⋮

initial_value_temp = operate(input[last], initial_value);
output[last] = initial_value;
initial_value = initial_value_temp

但是,当您尝试对其应用 execution::par 时,出于某种原因,可能是为了更好的并行化,它的工作方式如下:

output[0] = initial_value;
initial_value = operate(input[0], initial_value);

output[1] = initial_value;
initial_value = operate(input[1], initial_value);

     ⋮

output[last] = initial_value;
initial_value = operate(input[last], initial_value);

如果inputoutput 不同,它们的工作方式应该完全相同。但是,当它们相同时,该过程就会中断,这正是您尝试做的。

要修复它,最简单的方法是创建一个输出容器:

std::vector<int> input{1,2,3,4,5,6,7,8,9};

std::vector<int> output;
output.reserve(input.size());

std::exclusive_scan(std::execution::par, 
                    std::begin(input), 
                    std::end(input), 
                    std::back_inserter(output),
                    1, std::multiplies{});

  • 注意execution::par 实际上会尝试将整个任务分配到不同的线程中,然后再将它们合并。有很多关于它应该如何工作的文章。但是,这里的要点是您试图在生成输出的同时编辑输入。而且只有 9 个数字,它从来没有为我创建任何并行线程(创建一个可能会慢得多)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-07-06
    • 2022-10-07
    • 2012-04-01
    • 1970-01-01
    • 2020-02-04
    • 1970-01-01
    • 2020-12-13
    相关资源
    最近更新 更多