我刚刚开始使用 OpenMP 指令来使用多个线程。然而,这段代码使用单线程版本运行得最快。在我看来,算法应该可以很好地扩展,因为计算是独立的。这里发生了什么事?如何改进代码?
#include <omp.h>
std::vector<Track> interpolateTracks(const std::vector<Track>& tracks, double segmentLength) {
typedef std::vector<Track>::const_iterator iterator;
std::vector<Track> list;
#pragma omp parallel shared(list, tracks, segmentLength)
{
std::vector<Track> local;
iterator myBegin = threadBegin(tracks.begin(), tracks.end());
iterator myEnd = threadEnd(tracks.begin(), tracks.end());
for (iterator i = myBegin; i < myEnd; ++i) {
const Track& t = *i;
TrackInterpolator interpol(t);
const Track& result = interpol.bySegmentLength(segmentLength);
local.push_back(result);
}
#pragma omp critical
{
list.insert(list.end(), local.begin(), local.end());
std::cout << "Done: " << omp_get_thread_num() << std::endl;
}
}
return list;
}
根据当前线程数和线程数定义的函数beginThread(begin, end)
和endThread(begin,end)
返回范围的小块。begin
end
这是他们的实现:
#include <omp.h>
template <class I>
I threadBegin(I begin, I end) {
int part = omp_get_thread_num();
int parts = omp_get_num_threads();
double chunk = (end - begin)*1.0/parts;
ptrdiff_t diff = (ptrdiff_t) (chunk*part);
return begin + diff;
}
template <class I>
I threadEnd(I begin, I end) {
//the end of i is the begin of i+1
int part = omp_get_thread_num() + 1;
int parts = omp_get_num_threads();
if (part == parts) {
return end;
} else {
double chunk = (end - begin)*1.0/parts;
ptrdiff_t diff = (ptrdiff_t) (chunk*part);
return begin + diff;
}
}
我在 16 核的 linux 机器上运行代码。
不幸的是,我只能访问有点过时的 gcc ((SUSE Linux) 4.5.1 20101208),以防万一这可能是原因。
list.push_back(..)
PS 我的第一个版本在关键部分使用了并行 for 循环,这甚至比此处发布的变体还要慢。