2013-03-04 63 views
10

我有一個可以並行化的C++程序。我正在使用Visual Studio 2010,32位編譯。並行任務使用boost :: thread比使用ppl或OpenMP獲得更好的性能

在節目的短的結構如下

#define num_iterations 64 //some number 

struct result 
{ 
    //some stuff 
} 

result best_result=initial_bad_result; 

for(i=0; i<many_times; i++) 
{ 
    result *results[num_iterations]; 


    for(j=0; j<num_iterations; j++) 
    { 
     some_computations(results+j); 
    } 

    // update best_result; 
} 

由於每個some_computations()是獨立的(一些全局變量讀取,但沒有全局變量修改)我並行內for -loop。

我第一次嘗試用的boost ::線程

thread_group group; 
for(j=0; j<num_iterations; j++) 
{ 
    group.create_thread(boost::bind(&some_computation, this, result+j)); 
} 
group.join_all(); 

效果還不錯,但我還是決定嘗試更多。

我試過的OpenMP

#pragma omp parallel for 
for(j=0; j<num_iterations; j++) 
{ 
    some_computations(results+j); 
} 

的結果比boost::thread的更爲惡劣。

然後我嘗試了PPL庫和使用parallel_for()

Concurrency::parallel_for(0,num_iterations, [=](int j) { 
    some_computations(results+j); 
}) 

的結果是最差的。

我發現這種行爲相當令人驚訝。由於OpenMP和ppl是爲並行化設計的,因此我期望得到比boost::thread更好的結果。我錯了嗎?

爲什麼boost::thread能給我更好的結果?

+2

您能否定量「更好」,例如提供執行時間與線程數量的比較?用'boost :: thread'你創建了64個線程。 OpenPM使用一組工作線程,其數量默認爲虛擬CPU的數量。 PPL還使用線程池,並且比OpenMP的開銷更高,因爲它還實現了工作平衡。 – 2013-03-05 09:38:29

+0

對於每次嘗試,我都使用相同的數字(32或64),可能如您所指出的那樣,使用OpenMP和ppl我可以獲得更好的結果,將線程數設置爲等於核心數。我會盡力。 – 888 2013-03-05 10:07:40

+1

現在回答這個問題幾乎是不可能的。什麼是'some_computations'在做什麼?我可能在某處存在爭用(這可能會以不同的方式觸發不同的庫,例如,如果openmp實際上開銷較低,但是對共享緩存線的寫入很多,導致緩存失效狂熱可能實際上會使緩慢)?每個變體 – Grizzly 2013-03-07 18:56:46

回答

9

OpenMP或PPL不會做悲觀的事情。他們只是按照他們的說法去做,但是當你試圖平行循環時,你應該考慮一些事情。

沒有看到你如何實現這些東西,很難說真正的原因可能是什麼。

此外,如果每次迭代中的操作都對同一循環中的任何其他迭代具有一定的依賴性,那麼這將創建爭用,這會減慢速度。你沒有顯示你的some_operation函數實際做了什麼,所以很難判斷是否存在數據依賴關係。

一個可以真正並行化的循環必須能夠使每個迭代完全獨立於所有其他迭代運行,在任何迭代中都不會訪問共享內存。所以最好,你會寫東西到本地變量,然後在最後複製。

並非所有的循環都可以並行化,這非常依賴於正在完成的工作類型。

例如,對於並行化來說很好的事情是在屏幕緩衝區的每個像素上進行的工作。每個像素完全獨立於所有其他像素,因此,一個線程可以進行一次循環迭代,並且無需等待迭代之間的循環內的共享內存或數據依賴性即可完成工作。另外,如果你有一個連續的數組,那麼這個數組可能部分在緩存行中,如果你正在編輯線程A中的元素5,然後改變線程B中的元素6,你可能會得到緩存爭用,這將會也會放慢速度,因爲這些會駐留在同一個緩存行中。現象稱爲虛假分享

在進行循環並行化時,需要考慮很多方面。

+0

運行並行塊需要多長時間,函數some_operation將一個偏移量存入一個數組中,並且該數組在多個線程之間共享。我不知道PPL或OpenMP可以使任何你不寫入該數組的內容,或者其他任何內容寫入該數組。所以我的答案不會改變。 – 2013-03-04 17:30:36

+1

您的第一段不正確。 OpenMP和PPL都不關心你對共享變量所做的事情,它們的工作方式也沒有什麼悲觀或樂觀的。兩者都是命令式的編程概念,這意味着編譯器如果將其告知並行處理,而不是將表達式視爲提示,那麼編譯器就會使其平行。對共享變量的適當處理完全留給程序員。 – 2013-03-05 09:43:19

2

簡而言之,openMP主要基於共享內存,額外的任務管理和內存管理成本。 ppl旨在處理常見數據結構和算法的通用模式,它帶來了額外的複雜性成本。他們兩個都有額外的CPU成本,但是你簡單的掉線boost線程不(boost線程只是簡單的API包裝)。這就是爲什麼他們都比你的boost版本慢。而且,由於示例計算彼此獨立,沒有同步,因此openMP應接近boost版本。

它發生在簡單的場景中,但對於複雜的場景,具有複雜的數據佈局和算法,它應該與上下文相關。

+2

OpenMP不是爲消息傳遞而設計的,MPI是通過masseges的。 – Moss 2013-03-13 12:06:20

+1

@Moss,謝謝,我混淆了OpenMP和MPI。 OpenMP是基於共享內存的。 – 2013-03-13 23:17:48