openMp:parallelize std :: map iteration

时间:2015-05-29 11:54:52

标签: c++ openmp stdmap

有一些关于这个问题的帖子,但没有一个满足我。 我没有openMp 3.0支持,我需要在地图上并行化迭代。我想知道这个解决方案是否有效:

auto element = myMap.begin();

#pragma omp parallel for shared(element)
for(int i = 0 ; i < myMap.size() ; ++i){
 MyKeyObject * current_first = nullptr;
 MyValueObject * current_second = nullptr;
#pragma omp critical
{
    current_first = element->first;
    current_second = element->second;
    ++element;
}

// Here I can use 'current' as in a usual loop
}

所以我使用for循环只是为了确保线程将处理相同数量的地图元素。这是正确的猜测还是会失败?

ps:我正在开发visual studio 2012,所以如果你有关于如何让我的编译器支持openMp 3.0的提示,这也可以解决我的问题..

3 个答案:

答案 0 :(得分:9)

这不是您问题的直接答案,但我会尝试为您节省一些未来糟糕的“OpenMP with Visual Studio”体验。

Microsoft C / C ++编译器仅支持OpenMP 2.0。由于OpenMP内置于编译器内核并且不是附加软件包(除非有人提出外部源到源转换引擎),并且微软似乎不是,所以无法使其支持OpenMP 3.0或更高版本。有兴趣在推动自己的解决方案的同时提供进一步的OpenMP支持(见下文)。因此,您应该获得与Visual Studio集成的英特尔C / C ++编译器或者像GCC或PGI C / C ++编译器这样的独立编译器。

如果您是专门针对Windows开发的,那么您可能希望放弃OpenMP并使用Concurrency Runtime,特别是PPL。 PPL附带Visual Studio 2012及更新版本,并为STL中的某些算法提供数据和任务并行等效项。您感兴趣的是concurrency::parallel_for_each(),它是std::for_each()的并行版本。它适用于前向迭代器,虽然不如随机迭代器那样有效。但是你必须确保处理地图的一个元素需要至少一千条指令,否则并行化将不会有益。

如果您的目标是跨平台兼容性,那么Intel Threading Building Blocks(简称英特尔TBB)是PPL的替代方案。它提供tbb::parallel_do()算法,该算法专门用于处理前向迭代器。关于每个地图元素的工作量的相同警告适用。

答案 1 :(得分:2)

您的方法将起作用,因为您在关键部分中访问并迭代共享对象@row.Date.ToString("dd-MM-yyyy") 。无论这不是对性能有益,你都必须进行测试。这是您可能想要考虑的替代方法。我称之为“快进”方法。

我们假设你想并行执行此操作

element

您可以使用OpenMP 2.0

执行此操作
for(auto element = myMap.begin(); element !=myMap.end(); ++element) {
    foo(element->first, element->second);
}

每个线程都运行#pragma omp parallel { size_t cnt = 0; int ithread = omp_get_thread_num(); int nthreads = omp_get_num_threads(); for(auto element = myMap.begin(); element !=myMap.end(); ++element, cnt++) { if(cnt%nthreads != ithread) continue; foo(element->first, element->second); } } 个迭代器。但是,每个帖子只会调用myMap.size() foo。您的方法只运行myMap.size()/num_threads迭代器。但是,它需要在每次迭代时使用临界区。

只要通过nthreads迭代器“快进”的时间远小于myMap.size()/num_threads的时间,快进方法就是有效的,即:

foo

但是,如果nthreads*time(++elements) << time(foo) 的时间是有序的,那么迭代的时间和foo正在读/写内存,那么foo可能是内存带宽限制的,并且不会随着无论如何,线程的数量。

答案 2 :(得分:0)

你的方法不起作用 - 因为概念问题和一些错误的混合。

  1. [bug]你总会错过第一个元素,因为你要做的第一件事就是增加元素迭代器。
  2. [bug]所有线程将迭代整个映射,因为元素迭代器不是共享的。顺便说一句,目前还不清楚共享变量'part'在你的代码中是什么。
  3. 如果您使元素共享,那么访问它的代码(在临界区之外)将看到它当前指向的内容,而不管线程如何。你最终会处理一些元素而不是一些 - 根本不处理。
  4. 没有简单的方法来使用迭代器并行化对地图的访问,因为map迭代器不是随机访问。您可能希望手动拆分密钥,然后在不同的线程上使用密钥集的不同部分。