[英]OpenMP parallel code slower
我有兩個要並行化的循環
#pragma omp parallel for
for (i = 0; i < ni; i++)
for (j = 0; j < nj; j++) {
C[i][j] = 0;
for (k = 0; k < nk; ++k)
C[i][j] += A[i][k] * B[k][j];
}
#pragma omp parallel for
for (i = 0; i < ni; i++)
for (j = 0; j < nl; j++) {
E[i][j] = 0;
for (k = 0; k < nj; ++k)
E[i][j] += C[i][k] * D[k][j];
}
奇怪的是,即使使用大量線程,順序執行也比並行版本要快得多。 難道我做錯了什么? 請注意,所有數組都是全局的。 這有什么區別嗎?
並行外部循環的迭代共享其內部循環的索引變量( j
和k
)。 這肯定會使您的代碼比您預期的要慢一些,即,您的循環不會“尷尬” (或“令人愉快”)並行和並行循環迭代需要以某種方式從共享內存訪問這些變量。
更糟糕的是,因此,您的代碼包含競爭條件 。 結果,它將無法確定地運行。 換句話說:您的並行矩陣乘法實現現在不正確! (繼續檢查計算結果。))
您要做的是確保外部循環的所有迭代都具有索引變量j
和k
的專用副本。 您可以通過在並行循環范圍內聲明以下變量來實現此目的:
int i;
#pragma omp parallel for
for (i = 0; i < ni; i++) {
int j1, k1; /* explicit local copies */
for (j1 = 0; j1 < nj; j1++) {
C[i][j1] = 0;
for (k1 = 0; k1 < nk; ++k1)
C[i][j1] += A[i][k1] * B[k1][j1];
}
}
#pragma omp parallel for
for (i = 0; i < ni; i++) {
int j2, k2; /* explicit local copies */
for (j2 = 0; j2 < nl; j2++) {
E[i][j2] = 0;
for (k2 = 0; k2 < nj; ++k2)
E[i][j2] += C[i][k2] * D[k2][j2];
}
}
或在循環編譯中將它們聲明為private
:
int i, j, k;
#pragma omp parallel for private(j, k)
for (i = 0; i < ni; i++)
for (j = 0; j < nj; j++) {
C[i][j] = 0;
for (k = 0; k < nk; ++k)
C[i][j] += A[i][k] * B[k][j];
}
#pragma omp parallel for private(j, k)
for (i = 0; i < ni; i++)
for (j = 0; j < nl; j++) {
E[i][j] = 0;
for (k = 0; k < nj; ++k)
E[i][j] += C[i][k] * D[k][j];
}
這些更改會使並行實現比順序實現更快嗎? 很難說。 這取決於您的問題大小。 並行化(特別是通過OpenMP進行並行化)會帶來一些開銷。 僅當產生足夠的並行工作時,在並行線程上分配工作的收益才會超過產生的間接費用。
為了找出足以滿足您的代碼和軟件/硬件平台需求的工作量,建議您以不同的矩陣大小運行代碼以進行實驗。 然后,如果您還期望矩陣尺寸太小而無法作為計算的輸入,則可能需要使並行處理成為條件處理(例如,使用if
-clauses修飾循環編譯):
#pragma omp parallel for private (j, k) if(ni * nj * nk > THRESHOLD)
for (i = 0; i < ni; i++) {
...
}
#pragma omp parallel for private (j, k) if(ni * nl * nj > THRESHOLD)
for (i = 0; i < ni; i++) {
...
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.