OpenMP线程之间的矢量填充
Vector filling across OpenMP threads
我有一个算法,其中一个目标是填充向量。为了提高性能,算法的迭代分布在OpenMP线程中。我想知道哪种方式可以提供更好/更安全的矢量填充方式。
注意,向量的排序必须一致(即vec1的值n必须来自与vec2的值n相同的迭代。)
假设1:
std::vector<BasicType> vec1;
std::vector<BasicType> vec2;
#pragma opm parallel for
for(...)
{
// Do some intensive stuff to compute val1 and val2
// ...
#pragma omp critical
{
vec1.push_back(val1);
vec2.push_back(val2);
}
}
// Then go on to work with vec1 and vec2...
假设2:
std::vector<BasicType> vec1;
std::vector<BasicType> vec2;
#pragma opm parallel
{
std::vector<BasicType> vec1local;
std::vector<BasicType> vec2local;
#pragma omp for
for(...)
{
// Do some intensive stuff to compute val1 and val2
// ...
vec1local.push_back(val1);
vec2local.push_back(val2);
}
#pragma omp critical
{
// See note 1 below
vec1.insert(vec1.end(), vec1local.begin(), vec1local.end());
vec2.insert(vec2.end(), vec2local.begin(), vec2local.end());
}
}
// Then go on to work with vec1 and vec2...
注1:这取自将矢量附加到矢量的最佳方式
注意2:似乎val1和val2可以在某个对象中组合,以保持一致性,并且只适用于一个向量,但就目前而言,对于算法的其余部分来说,这似乎是不切实际的。
注意3:为了给出一个数量级,for
循环包含大约100次迭代,分为4个线程。除了极少数例外,每个迭代都应该有相同的工作负载(这会导致关键部分在同一时间发生的问题)
注意4:仅供记录,整个过程涉及图像稳定,并在Tegra K1架构上运行。使用的编译器是gcc 4.8.4。
从你的两个建议中,我更喜欢第一个。它更简单,不需要额外的内存。然而,我建议一种没有critical
部分的替代方案:
std::vector<BasicType> vec1(size);
std::vector<BasicType> vec2(size);
#pragma opm parallel for
for(...)
{
// Do some intensive stuff to compute val1 and val2
// ...
vec1[i] = val1;
vec2[i] = val2;
}
请注意,这可能会由于缓存线盗用而导致一些性能问题。然而,我不会担心这一点,除非这是一个通过实际性能分析验证的实际问题。解决方案可能是:
- 使用第二个解决方案。(这需要花费内存和额外的后处理)
- 对齐你的向量,并为循环使用适当的块。(这样每个线程都有本地缓存行)
- 使用内部包含局部矢量,但外部提供必要的全局矢量运算的数据结构。(总的来说,这可能是最好的解决方案。)
我假设您需要使用向量,而不能使用数组(尽管您的问题不是很有趣)。使用t = omp_get_num_threads()
,您可以并行填充矢量,然后将它们合并到log2(t)
操作中,而不是像以下那样的t
操作中
void reduce(std::vector<BasicType> *v1, std::vector<BasicType> *v2, int begin, int end) {
if(end - begin == 1) return;
int pivot = (begin+end)/2;
#pragma omp task
reduce(v, begin, pivot);
#pragma omp task
reduce(v, pivot, end);
#pragma omp taskwait
v1[begin].insert(v1[begin].end(), v1[pivot].begin(), v1[pivot].end());
v2[begin].insert(v2[begin].end(), v2[pivot].begin(), v2[pivot].end());
}
和
std::vector<BasicType> v1, v2;
std::vector<BasicType> *v1p, *v2p;
#pragma omp parallel
{
#pragma omp single
{
v1p = new std::vector<BasicType>[omp_get_num_threads()];
v2p = new std::vector<BasicType>[omp_get_num_threads()];
}
#pragma omp for
for(...) {
// Do some intensive stuff to compute val1 and val2
// ...
v1p[omp_get_thread_num()].push_back(val1);
v2p[omp_get_thread_num()].push_back(val2);
}
#pragma omp single
reduce(v1p, v2p, 0, omp_get_num_threads());
}
v1 = v1p[0], v2 = v2p[0];
delete[] v1p;
delete[] v2p;
例如,对于8个线程,这将加入线程的向量
(0,1) (2,3) (4,5) (6,7)
(0,2) (4,6)
(0,4)
有关并行填充矢量的更多信息,请参阅。有关在log2(t)
操作中合并线程的更多信息,请参阅此问题的答案。
相关文章:
- 从不同线程使用int64的不同字节安全吗
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 在C++中使用cURL和多线程
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 在cuda线程之间共享大量常量数据
- 如何将元素添加到数组的线程安全函数?
- 线程,如果else语句,都是错误的上下文切换后,会发生什么
- 如何在<N>不发生内存泄漏的情况下同时(线程安全)填充 c++11 std::map<std::string,std::bitset*>?
- 填充和保存线程之间的共享缓冲区
- C++使用多线程的无序列图填充
- 当结构数组在主线程中填充数据时,从结构数组的低索引元素读取是否线程安全
- 优化寄存器/L1中数据的每线程复制和0填充
- boost线程未填充通过引用传递的本地对象
- 尝试用函数填充线程向量 - 错误
- OpenMP线程之间的矢量填充
- 填充计数'buckets' CUDA 线程
- 在CUDA内核中填充一个数组或列表,但不是在每个线程中
- c++使用' .reserve() '填充' std::vector '作为防止多线程缓存无效和错误共享的一种方
- 在单独的线程上填充、填充QTreeView树
- C/ c++线程调用填充内存