我有一个有序整数向量的循环。在循环内部,我对整数执行一些操作,以确定是否为程序的其余部分保留或丢弃它们。在循环之后,我需要一个包含保持整数的向量,也是有序的。
由于整数向量相当大(可能大约为50亿),我使用openmp来并行化循环,我想出了以下代码。为了保持良好的整数排序,我使用静态子句和私有向量,它们在循环完成后合并。
std::vector<unsigned> large_int_vector;
// vector filling and ordered...
std::vector<std::vector<unsigned> > good_int_threads;
#pragma omp parallel
{
int num_threads = omp_get_num_threads();
int i_thread = omp_get_thread_num();
#pragma omp single
{
good_int_threads.resize(num_threads);
}
#pragma omp for schedule(static)
for (std::size_t i = 0; i < large_int_vector.size(); i++) {
bool is_good_int = true;
// some operations on large_int_vector[i]
if (is_good_int)
good_int_threads[i_thread].push_back(large_int_vector[i]);
}
}
std::vector<unsigned> good_int;
for (unsigned i = 0; i != good_int_threads.size(); i++) {
good_int.insert(good_int.end(),good_int_threads[i].begin(),good_int_threads[i].end());
}
这可以正常工作,但不能很好地扩展。原因是大多数(它取决于线程的数量,但通常> 50%,如果仅使用2或3个线程,则可以高达100%)良好整数位于large_int_vector的“开头”。
更确切地说,for循环中完成的工作是将一些操作应用于整数。如果单个失败,则丢弃整数,我们可以立即移动到下一个整数。另一方面,对于要保留的整数,它必须通过所有操作。显然,这会导致工作不平衡,这可以解释不良规模。
good_int的大小通常为~large_int_vector / 50,因此大约为10亿。
我怎样才能改进我的代码?
答案 0 :(得分:0)
为每个线程的每个线程分配向量,并运行这样的块:
std::vector<unsigned> large_int_vec;
std::size_t n = large_int_vec.size();
std::size_t chunk = n/10; //10 chunks, adjust by performance.
#pragma omp parallel
{
std::vector<unsigned> good_int_local;
for(std::size_t j = 0; j < n; j += chunk) {
std::size_t n2 = (j + chunk) >= n ? n - j : chunk;
#pragma omp for nowait schedule(static)
for (std::size_t i = 0; i < n2; i++) {
bool is_good_int = true;
// some operations on large_int_vec[i]
if (is_good_int) good_int_local.push_back(large_int_vec[j + i]);
}
#pragma omp for schedule(static) ordered
for(int i=0; i<omp_get_num_threads(); i++) {
#pragma omp ordered
good_int.insert(good_int.end(), good_int_local.begin(), good_int_local.end());
}
good_int_local.clear();
}
}
这应该更好地平衡负载并保持顺序。您可以使用schedule(static, chunk)
来提供一个解决方案,它可以在不使用外部循环的情况下保留顺序,但对我来说这似乎并非易事。你也许可以提出一个custom dynamic solution但是再次保持秩序似乎并非易事。