【问题标题】:TBB Thread Local Set Using combinable or enumerable_thread_specific?TBB 线程本地集使用combinable 或enumerable_thread_specific?
【发布时间】:2015-05-16 12:04:06
【问题描述】:

我想在一个大型数据集上运行 tbb::parallel_for 并生成一个唯一集。在 parallel_for 主体中包含一些额外的逻辑,用于确定原始数据集的每个子元素是否应包含在该集合中。结果集通常比原始数据集小得多,我宁愿不计算具有重复项的向量并在之后删除重复项,因为这会增加内存使用量。

我的第一个实现使用 tbb::concurrent_unordered_set,通过分析,我注意到 set.insert() 方法存在明显的性能瓶颈。

我尝试改进这一点是尝试使用线程本地存储来为每个线程生成一个集合,然后在最后组合这些集合以删除原子。

尽管阅读了大量文档,但我仍然不确定 tbb::combinable 或 tbb::enumerable_thread_specific 是否最适合。

这一定是一个相当常见的用例。有人可以提供示例实现或指向我可以查看的在线示例吗?

【问题讨论】:

    标签: c++ multithreading unique tbb thread-local-storage


    【解决方案1】:

    我认为你正朝着正确的方向前进。并发哈希表对于大量元素(数千个)是有效的。尽管您仍然可以在运行算法之前尝试保留足够的容量并使用concurrent_unordered_set(设置为1)的负载因子并尝试concurrent_hash_map(在没有访问器的情况下使用insert(value)时更快,它也需要预留一些容量)。

    tbb::combinabletbb::enumerable_thread_specific 都使用相同的后端实现。区别仅在于界面。 documentation 有后者的例子,我重新设计了一下:

    typedef tbb::enumerable_thread_specific< std::pair<int,int> > CounterType;
    CounterType MyCounters (std::make_pair(0,0));
    
    int main() {
        tbb::parallel_for( tbb::blocked_range<int>(0, 100000000),
          [](const tbb::blocked_range<int> &r) {
            CounterType::reference my_counter = MyCounters.local();
            ++my_counter.first; my_counter.second += r.size();
        });
    
        std::pair<int,int> sum = MyCounters.combine(
            [](std::pair<int,int> x, std::pair<int,int> y) {
                return std::make_pair(x.first+y.first, x.second+y.second);
            });
        printf("Total calls to operator() = %d, "
             "total iterations = %d\n", sum.first, sum.second);
    }
    

    最后,尝试另一种方法,使用tbb::parallel_reduce,您不需要像combinable这样的额外方法,而且减少主要是并行完成(仅记录P个顺序步骤,而组合线程特定值需要顺序访问所有P 元素)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-11
      • 1970-01-01
      相关资源
      最近更新 更多