tbb:并行查找第一个元素

时间:2011-10-11 13:31:54

标签: c++ design-patterns parallel-processing tbb

我遇到了这个问题:

  • 查找列表中的第一个元素,给定条件成立。

不幸的是,列表很长(100.000个元素),并且使用一个Thread评估每个元素的条件总共花费大约30秒。

有没有办法干净地并行化这个问题?我查看了所有的tbb模式,但找不到合适的东西。

更新:出于性能原因,我希望在找到项目时尽早停止并停止处理列表的其余部分。这就是为什么我认为我无法使用parallel_whileparallel_do

9 个答案:

答案 0 :(得分:1)

我对这个图书馆并不太熟悉,但只是大声思考,难道你不能让一组线程在不同的凝视点同步进行不同的迭代吗?

假设你决定拥有n个线程(=核心数或其他),每个线程应该被赋予一个特定的起始点,直到n,所以第一个线程从{{1}开始},它比较的下一个项目是begin()等。第二个帖子在begin() + n开始,然后它的下一个比较也在begin()+1等等。

这样你可以让一组线程在列表中并行迭代,迭代本身可能并不昂贵 - 只是比较。没有节点会被多次比较,你可以有一些条件,当任何一个线程匹配时都会设置这个条件,并且所有条件都应该在迭代/比较之前检查这个条件。

我认为实施(?)

非常简单

答案 1 :(得分:1)

我认为使用TBB解决此问题的最佳方法是parallel_pipeline

管道中应该(至少)有两个阶段。第一阶段是连续的;它只是从列表中读取下一个元素并将其传递给第二阶段。第二阶段是平行的;它评估给定元素的感兴趣条件。一旦满足条件,第二阶段就会设置一个标志(应该是原子标志或用锁保护)以指示找到解决方案。第一阶段必须检查此标志,并在找到解决方案后停止阅读列表。

由于条件评估是针对少数元素并行执行的,因此找到的元素可能不是列表中第一个合适的元素。如果这很重要,您还需要保留元素的索引,并在找到合适的解决方案时检测其索引是否小于先前已知解决方案的索引(如果有)。

HTH。

答案 2 :(得分:1)

好的,我这样做了:

  1. 将所有元素放入tbb::concurrent_bounded_queue<Element> elements
  2. 创建一个空的tbb::concurrent_vector<Element> results
  3. 创建一个boost::thread_group,并创建几个运行此逻辑的线程:
  4. 并行运行的逻辑:

    Element e;
    while (results.empty() && elements.try_pop(e) {
        if (slow_and_painfull_check(e)) {
             results.push_back(e);
        }
    }
    

    因此,当找到第一个元素时,所有其他线程将在下次检查results.empty()时停止处理。

    两个或多个线程可能正在处理slow_and_painfull_check返回true的元素,因此我只是将结果放入向量中并在并行循环之外处理它。

    线程组中的所有线程完成后,我会检查results中的所有元素并使用最先出现的元素。

答案 3 :(得分:0)

答案 4 :(得分:0)

如果您使用GCC,GNU OpenMP提供并行标准功能 link

答案 5 :(得分:0)

我在这里看到两个并行机会:在多个线程上评估一个元素,或者在不同的线程上一次评估多个元素。

没有足够的信息来确定在多个线程上评估一个元素的难度和有效性。如果这很容易,每个元素时间可以减少30秒。

对于这个问题,我没有看到TBB干净利落。列表没有随机访问迭代器,确定何时停止以及保证找到第一个元素存在问题。可能会有一些游戏你可以使用这些游戏来实现它。

您也可以使用一些较低级别的线程构造来自行实现,但是有很多地方可以返回不正确的结果。为防止出现此类错误,我建议使用现有算法。您可以将列表转换为数组(或具有随机访问迭代器的其他结构),并使用实验性libstdc ++ Parellel模式find_if算法user383522引用。

答案 6 :(得分:0)

如果它是一个链表,并行搜索不会增加太多速度。但是,链接列表往往在缓存方面表现不佳。如果你有两个线程,你可能会获得微小的性能提升:一个是find_first_element,一个只是遍历列表,确保在第一个线程之前不要超过X(100?)。第二个线程不进行任何比较,但会确保第一个线程尽可能缓存项目。这个可能可以帮助你的时间,或者它可能没什么区别,或者它可能会阻碍。测试一切。

答案 7 :(得分:0)

您无法将列表转换为平衡树或类似树吗?这样的数据结构更容易并行处理 - 通常你会收回你在第一次使它平衡时所付出的开销......例如,如果你编写功能样式代码,请查看本文:{{3} }

答案 8 :(得分:-1)

我从来没有听说过英特尔tbb库,但快速打开并扫描了教程,让我看到了parallel_for,这似乎可以解决问题。