[英]Parallelize nested for loop with respect to symmetry of all -against-all comparison with C++/OpenMP
我有一個比較所有元素的簡單問題。 比較本身是對稱的,因此不必進行兩次比較。
以下代碼示例通過顯示所訪問元素的索引來顯示我要尋找的內容:
int n = 5;
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
printf("%d %d\n", i,j);
}
}
輸出為:
0 1
0 2
0 3
0 4
1 2
1 3
1 4
2 3
2 4
3 4
因此,每個元素相互比較一次。 當我想並行化此代碼時,我遇到一個問題,首先我必須堅持動態調度,因為每個迭代的計算時間的確變化很大,並且由於嵌套的迭代是基於索引的事實,所以我不能使用崩潰。取決於外循環。
將#pragma omp parallel for schedule(dynamic, 3)
外部循環的#pragma omp parallel for schedule(dynamic, 3)
可能會導致最后執行單核,而將其用於內部循環可能會導致外部循環的每次迭代內執行此類操作。
有沒有更復雜的方法可以做到/做到這一點?
我還沒有仔細考慮過,但是您也可以嘗試這樣的方法:
int total = n * (n-1) / 2; // total number of combinations
#pragma omp parallel for
for (int k = 0; k < total; ++k) {
int i = first(k, n);
int j = second(k, n, i);
printf("%d %d\n", i,j);
}
int first(int k, int n) {
int i = 0;
for (; k >= n - 1; ++i) {
k -= n - 1;
n -= 1;
}
return i;
}
int second(int k, int n, int i) {
int t = i * (2*n - i - 1) / 2;
return (t == 0 ? k + i + 1 : (k % t) + i + 1);
}
實際上,OpenMP標准對崩潰的說法是:
每個關聯循環的迭代計數是在進入最外面的循環之前計算的。 如果任何關聯循環的執行更改了用於計算任何迭代計數的任何值,則該行為是不確定的。
因此,您無法折疊循環,這是最簡單的方法。 但是,由於您對索引對的計算順序並不特別感興趣,因此可以如下更改循環:
for ( int i = 0; i < n; i++ ) {
for ( int j = 0; j < n / 2; j++ ) {
int ii, jj;
if ( j < i ) {
ii = n - 1 - i;
jj = n - 1 - j;
}
else {
ii = i;
jj = j + 1;
}
printf( "%d %d\n", ii, jj );
}
}
這應該以某種混亂的順序為您提供所有想要的對,但是具有固定的迭代限制,可以實現平衡的並行化,甚至可以折疊循環。 簡而言之,如果n為偶數,則對應於n / 2的列將顯示兩次,因此您可以使用它,也可以稍微修改算法以避免這種情況...
我以前在以下方面取得了不錯的成績:
#pragma omp parallel for collapse(2)
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (j <= i)
continue;
printf("%d %d\n", i, j);
}
}
請記住, printf
並不會做任何並行的工作,因此最好在特定工作中進行分析。 您可以嘗試添加schedule(dynamic, 10)
或大於10
具體取決於您執行的迭代次數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.