有条件地并行填充向量

Posted

技术标签:

【中文标题】有条件地并行填充向量【英文标题】:conditionally filling a vector in parallel 【发布时间】:2018-11-22 12:37:11 【问题描述】:

我想写下面代码的多线程版本

template<typename Out, typename In, typename Cond, typename Func>
std::vector<Out> collect(std::vector<In> const&values,
                         Cond const&cond, Func const&func)

    std::vector<Out> result;
    for(auto const&val : values)
        if(cond(val))
            result.emplace_back(func(val));
    return result;

选择元素的顺序无关紧要。

一种简单的方法是

template<typename Out, typename In, typename Cond, typename Func>
std::vector<Out> collect(std::vector<In> const&values,
                         Cond const&cond, Func const&func)

    std::vector<Out> result(values.size());
    std::atomic<size_t> index = 0;
    // some multithreaded for loop implementation
    parallel_for(size_t(0),values.size(),[&](size_t i) 
        if(cond(values[i]))
            result[index++] = func(values[i]);
    );
    result.resize(index);
    return result;

(当然,初始化result 是串行的,但我们在这里忽略它)。这似乎有效,但可能不是无锁的。有没有更好的办法?特别是,我能否避免分配太多数据(如果只选择了少数输入数据)?

问题与std::copy_if 非常相似(应该是std::transform_if 它存在)——并行版本std::copy_if(std::par,...) 是如何实现的(它是C++17,但我仅限于C+ +11)?

【问题讨论】:

我不会让所有线程写入同一个向量,而是每个线程都写入自己的并最终合并它们,这样你只需要同步一次而不是“一直” 如果你已经使用了tbb(从你的parallel_for暗示),为什么还要使用std::vector来并发push_backtbb::concurrent_vector 专为并发访问而设计。 似乎高度依赖于您的确切细节,但复制到单独的向量和合并听起来不错。 @PasserBy +1,另外使用单独的向量,甚至写在同一向量的单独跨度中,真的会increase the performance。 @liliscent 我尝试了使用tbb::concurrent_vector 的建议,但发现这会导致性能下降。我怀疑它的实现并不能避免错误共享,因此会遇到与我的简单方法相同的问题。 【参考方案1】:

一个不错的方法是使用最后合并的线程局部向量。如果不是因为它使用 OMP,这个答案(特别是最后一个代码示例)将是一个很好的副本:

https://***.com/a/18671256/9528746

编辑:更改为更好的答案。

【讨论】:

主要区别不是OMP的东西,而是我只收集选定的项目。

以上是关于有条件地并行填充向量的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中并行查找向量的第一个

是否有一个足够智能的并行制造系统可以智能地响应低内存/交换条件?

如果前一列包含值,则有条件地填充列?

猫鼬有条件地填充子文档

Python Plotly Express:如何有条件地填充区域图?

使用 Mongoose 和 GraphQL 从填充模型有条件地返回值的最有效方法?