C ++ OpenMP Parallel For Loop - 替代std :: vector

C ++ OpenMP Parallel For Loop - 替代std :: vector 

基于这个线程,OpenMP和STL向量,哪些数据结构是并行for循环中共享 std :: vector的好选择?主要方面是速度,矢量可能需要在循环期间调整大小。



小唯快跑啊
浏览 1285回答 2
2回答

侃侃无极

您链接的问题是在“多个线程写入单个容器的情况下,STL向量容器不是线程安全的”这一事实。如果您调用可能导致重新分配std::vector持有的基础数组的方法,那么这只是正确的说法。push_back(),pop_back()并且insert()是这些危险方法的例子。如果您需要线程安全重新分配,那么库intel线程构建块为您提供并发向量容器。您不应该在单线程程序中使用tbb :: concurrent_vector,因为访问随机元素所花费的时间高于std :: vector执行相同操作所需的时间(即O(1))。然而,并发矢量电话push_back(),pop_back(),insert()在一个线程安全的方式,甚至当再分配发生。编辑1:以下英特尔演示文稿的幻灯片46和47 给出了使用tbb :: concurrent_vector并发重新分配的说明性示例编辑2:顺便说一句,如果你开始使用英特尔Tread Building Block(它是开源的,它适用于大多数编译器,它与C ++ / C ++ 11功能集成得比openmp好得多),那么你不需要使用openmp创建parallel_for,这是使用tbb的parallel_for的一个很好的例子。

HUWWW

我认为你可以std::vector在大多数时间使用OpenMP并且仍然具有良好的性能。例如,以下代码std::vectors并行填充,然后将它们组合在一起。只要您的主循环/填充功能是瓶颈,这通常可以很好地工作并且是线程安全的。std::vector<int>&nbsp;vec;#pragma&nbsp;omp&nbsp;parallel{ &nbsp;&nbsp;&nbsp;&nbsp;std::vector<int>&nbsp;vec_private; &nbsp;&nbsp;&nbsp;&nbsp;#pragma&nbsp;omp&nbsp;for&nbsp;nowait&nbsp;//fill&nbsp;vec_private&nbsp;in&nbsp;parallel &nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i=0;&nbsp;i<100;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vec_private.push_back(i); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;#pragma&nbsp;omp&nbsp;critical &nbsp;&nbsp;&nbsp;&nbsp;vec.insert(vec.end(),&nbsp;vec_private.begin(),&nbsp;vec_private.end());}编辑:OpenMP 4.0允许使用用户定义的缩减#pragma omp declare reduction。上面的代码可以简化为#pragma&nbsp;omp&nbsp;declare&nbsp;reduction&nbsp;(merge&nbsp;:&nbsp;std::vector<int>&nbsp;:&nbsp;omp_out.insert(omp_out.end(),&nbsp;omp_in.begin(),&nbsp;omp_in.end()))std::vector<int>&nbsp;vec;#pragma&nbsp;omp&nbsp;parallel&nbsp;for&nbsp;reduction(merge:&nbsp;vec)for(int&nbsp;i=0;&nbsp;i<100;&nbsp;i++)&nbsp;vec.push_back(i);编辑:到目前为止我所显示的内容并没有按顺序填充向量。如果订单很重要,那么这可以这样做std::vector<int>&nbsp;vec;#pragma&nbsp;omp&nbsp;parallel{ &nbsp;&nbsp;&nbsp;&nbsp;std::vector<int>&nbsp;vec_private; &nbsp;&nbsp;&nbsp;&nbsp;#pragma&nbsp;omp&nbsp;for&nbsp;nowait&nbsp;schedule(static) &nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i=0;&nbsp;i<N;&nbsp;i++)&nbsp;{&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vec_private.push_back(i); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;#pragma&nbsp;omp&nbsp;for&nbsp;schedule(static)&nbsp;ordered&nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i=0;&nbsp;i<omp_get_num_threads();&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#pragma&nbsp;omp&nbsp;ordered &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vec.insert(vec.end(),&nbsp;vec_private.begin(),&nbsp;vec_private.end()); &nbsp;&nbsp;&nbsp;&nbsp;}}这样可以避免为每个线程保存std :: vector,然后将它们串行合并到并行区域之外。我在这里了解了这个“技巧”&nbsp;。对于用户定义的缩减,我不确定如何做到这一点(或者甚至可能)。。用户定义的缩减不可能做到这一点。我刚刚意识到关键部分是不必要的,我从这个问题中找到了parallel-cumulative-prefix-sums-in-openmp-communic-values-between-thread。此方法也可以使订单正确std::vector<int>&nbsp;vec;size_t&nbsp;*prefix;#pragma&nbsp;omp&nbsp;parallel{ &nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;ithread&nbsp;&nbsp;=&nbsp;omp_get_thread_num(); &nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;nthreads&nbsp;=&nbsp;omp_get_num_threads(); &nbsp;&nbsp;&nbsp;&nbsp;#pragma&nbsp;omp&nbsp;single&nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;prefix&nbsp;=&nbsp;new&nbsp;size_t[nthreads+1]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;prefix[0]&nbsp;=&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;std::vector<int>&nbsp;vec_private; &nbsp;&nbsp;&nbsp;&nbsp;#pragma&nbsp;omp&nbsp;for&nbsp;schedule(static)&nbsp;nowait&nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i=0;&nbsp;i<100;&nbsp;i++)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vec_private.push_back(i); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;prefix[ithread+1]&nbsp;=&nbsp;vec_private.size(); &nbsp;&nbsp;&nbsp;&nbsp;#pragma&nbsp;omp&nbsp;barrier&nbsp;&nbsp;&nbsp;&nbsp;#pragma&nbsp;omp&nbsp;single&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i=1;&nbsp;i<(nthreads+1);&nbsp;i++)&nbsp;prefix[i]&nbsp;+=&nbsp;prefix[i-1]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vec.resize(vec.size()&nbsp;+&nbsp;prefix[nthreads]); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;std::copy(vec_private.begin(),&nbsp;vec_private.end(),&nbsp;vec.begin()&nbsp;+&nbsp;prefix[ithread]);}delete[]&nbsp;prefix;
打开App,查看更多内容
随时随地看视频慕课网APP