我撰寫了一個程式來計算一個包含 1M 個數字的陣列的總和,其中所有元素 = 1。我使用 OpenMP 進行多執行緒處理。但是,運行時間不會隨著執行緒數而變化。這是代碼:
#include <iostream>
#include <omp.h>
#define SIZE 1000000
#define N_THREADS 4
using namespace std;
int main() {
int* arr = new int[SIZE];
long long sum = 0;
int n_threads = 0;
omp_set_num_threads(N_THREADS);
double t1 = omp_get_wtime();
#pragma omp parallel
{
if (omp_get_thread_num() == 0) {
n_threads = omp_get_num_threads();
}
#pragma omp for schedule(static, 16)
for (int i = 0; i < SIZE; i ) {
arr[i] = 1;
}
#pragma omp for schedule(static, 16) reduction( :sum)
for (int i = 0; i < SIZE; i ) {
sum = arr[i];
}
}
double t2 = omp_get_wtime();
cout << "n_threads " << n_threads << endl;
cout << "time " << (t2 - t1)*1000 << endl;
cout << sum << endl;
}
N_THREADS 不同值的運行時間(以毫秒為單位)如下:
n_threads 1
time 3.6718
n_threads 2
time 2.5308
n_threads 3
time 3.4383
n_threads 4
time 3.7427
n_threads 5
time 2.4621
我曾經schedule(static, 16)使用每個執行緒 16 次迭代的塊來避免錯誤共享問題。我認為性能問題與錯誤共享有關,但現在我認為不是。可能是什么問題?
uj5u.com熱心網友回復:
您的代碼受記憶體限制,計算成本不高。它的速度取決于記憶體訪問的速度(快取利用率、記憶體通道數量等),因此預計它不會隨著執行緒數量的增加而很好地擴展。
更新,我使用 1000 倍大的 SIZE(即#define SIZE 100000000)(g -fopenmp -O3 -mavx2)運行此代碼
這是結果,它仍然隨著執行緒數的增加而嚴重擴展:
n_threads 1
time 652.656
time 657.207
time 608.838
time 639.168
1000000000
n_threads 2
time 422.621
time 373.995
time 425.819
time 386.511
time 466.632
time 394.198
1000000000
n_threads 3
time 394.419
time 391.283
time 470.925
time 375.833
time 442.268
time 449.611
time 370.12
time 458.79
1000000000
n_threads 4
time 421.89
time 402.363
time 424.738
time 414.368
time 491.843
time 429.757
time 431.459
time 497.566
1000000000
n_threads 8
time 414.426
time 430.29
time 494.899
time 442.164
time 458.576
time 449.313
time 452.309
1000000000
uj5u.com熱心網友回復:
5 個執行緒爭奪同一個累加器以減少或只有 16 個塊大小必須抑制回圈迭代的高效流水線。嘗試每個執行緒更粗糙的區域。
也許更重要的是,您需要以編程方式多次重復基準測驗以獲得平均值并將 CPU 快取/核心加熱到更高的頻率以進行更好的測量。
基準測驗結果顯示為 1MB/s。當然,最差的 RAM 會比那好 1000 倍。所以記憶體不是瓶頸(目前)。每 4 秒 100 萬個元素就像鎖定爭用或非加熱基準。通常,即使是 Pentium 1 也會產生比這更多的帶寬。你確定你是用 O3 優化編譯的?
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/333523.html
