【问题标题】:c++: OpenMP and non-random-access STL containers - a possible workaroundc++:OpenMP 和非随机访问 STL 容器 - 一种可能的解决方法
【发布时间】:2012-05-03 14:03:29
【问题描述】:

在 SO 和整个互联网上,对于如何使 OpenMP 的易于使用的 #pragma 指令与 C++ 的同样易于使用的 STL 容器配合使用存在很多困惑和挫败感。

每个人都在谈论 STL vector 的解决方法,但非随机访问/双向容器呢,例如 maplistset 等?

我遇到了这个问题,并设计了一个非常简单、明显的解决方法。我在这里为 STL map 介绍它,但它显然是可推广的。

系列版本:

for (std::map<A,B>::iterator it = my_map.begin();
        it != my_map.end();
        ++it)       
    { /* do work with  it   */  }

我提出的将 OpenMP 与 STL map 一起使用的解决方案:

    //make an array of iterators.
    int loop_length = my_map.size();
    std::map<A,B>::iterator loop_array[ loop_length ];

    std::map<A,B>::iterator allocate_it = my_map.begin();
    for (int j=0; j<loop_length; ++j)
        loop_array[j] = allocate_it++;

    // now you can use OpenMP as usual:
    #pragma omp parallel for
    for (uint j=0; j<loop_length; ++j) 
       { /* do work with    loop_array[j]    */  }

不过,我远非 OpenMP 专家,所以我想知道我提出的解决方法是否有效且良好。

请假定程序员负责在 for 循环中对 STL 容器进行线程安全处理。

最后,我提出的解决方案是否比以下普遍提出的解决方案(see answer to this SO Question) 更有效,因为在我的解决方案中,每个线程不会遍历整个容器?

#pragma omp parallel
{
    for (std::map<A,B>::iterator it = my_map.begin();
            it != my_map.end();
            ++it) 
    #pragma single nowait
       {   /*  do work  */   }

}

【问题讨论】:

  • 我怀疑这会更快(至少当AB 很大时,否则您可以将它们复制到vector 中)。但是你有没有尝试过你的问题?是不是更快?
  • @larsmans 我没有做过任何性能测试,也没有真正计划过(对不起)。我已经有一个以串行方式编写的大型复杂程序,到处都有 STL 容器,并且正在尝试对某些 STL-for-loop 进行多线程处理。因此,我不能轻易隔离和计时......
  • 即使您将容器的内容复制到vector 以进行测试也不行?
  • 对不起,如果我的问题很愚蠢,但您能不能简单地遍历j,然后通过allocate_it+j 访问元素,其中分配它的设置与您的帖子中一样。
  • @Azrael3000 但是迭代器算术不是只对随机访问迭代器有效吗(比如vector)? maplistset,只使用双向迭代器。

标签: c++ multithreading stl parallel-processing openmp


【解决方案1】:

OpenMP 从 3.0 版开始提供 task 构造,这对于与 STL 一起使用非常有用:

for (std::map<A,B>::iterator it = my_map.begin();
        it != my_map.end();
        ++it)       
{
   #pragma omp task
   { /* do work with  it   */  }
}

当然,迭代之间的数据依赖关系不应该存在。

【讨论】:

  • 是否有额外的开销由于循环内有 OpenMP 命令?一般来说,我认为通过并行化尽可能大的代码部分(例如嵌套循环中的最外层循环)可以最好地提高性能。
  • 这通常是正确的,但在 for 循环中使用 omp for 需要快速的随机访问迭代器(例如,在恒定时间内运行)。据我所知,std::map 根本不提供随机访问迭代器,您应该模拟一个。
  • 是的,这就是我在“建议的解决方案”中尝试做的事情,通过创建传统的(随机访问)数组然后循环而不是直接使用地图。我只是担心您的方法会产生过多的开销(每次迭代的线程管理)。
  • OpenMP 不会为每个任务创建单独的线程。相反,任务被放在一个“包”中,然后每个线程窃取一个任务。我同事的研究表明,在大大简化编码的同时,开销几乎可以忽略不计。我并不是要说服您使用任务 - 只是尝试看看哪个更快,哪个需要更多编程。
猜你喜欢
  • 2012-09-16
  • 1970-01-01
  • 2010-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-03
  • 2020-07-01
相关资源
最近更新 更多