2012-01-24 94 views
4

我在計算pi時遇到了一些麻煩,我的蒙特卡羅方法並行化。這裏是循環的並行化:pi計算的OpenMP並行化速度很慢或者錯誤

#pragma omp parallel for private(i,x,y) schedule(static) reduction(+:count) 
    for (i = 0; i < points; i++) { 
    x = rand()/(RAND_MAX+1.0)*2 - 1.0; 
    y = rand()/(RAND_MAX+1.0)*2 - 1.0; 

    // Check if point lies in circle 
    if(x*x + y*y < 1.0) { count++; } 
    } 

的問題是,它低估了PI如果我使用schedule(static),其比串行執行要慢,如果我用schedule(dynamic)。我究竟做錯了什麼?我已經嘗試了其他方法來解決它(例如:Using OpenMP to calculate the value of PI),但它仍然比串行實施慢得多。

在此先感謝

+0

'rand()'線程安全嗎? – Mysticial

+0

@Mystical:看起來不是:http://stackoverflow.com/questions/6161322/using-rand-with-multiple-threads-in-c –

+0

我懷疑@Mysticial有正確的想法。 'rand'通常會有一個內部的「種子」,它基本上充當共享資源,在每次調用時強制序列化(否則冒着不正確的結果)。如果你有它,我會嘗試使用'rand_r'或(最好)'drand48_r'來代替。或者,考慮在C++ 11中引入的隨機數生成類 - 每個實例都有其自己的狀態,這應該避免序列化(但可能會使初始化非常棘手 - 多個線程創建相同的序列並不會帶來好處)。 –

回答

6

假設你正在使用的C庫rand函數,該函數不是可重入或線程安全的。 POSIX提供rand_r功能,但是(引述glibc的文檔):

POSIX.1擴展C標準功能以支持在多線程程序可再現的 隨機數。但是,擴展名爲 設計不合理,不適合進行嚴肅的工作。

特別地,種子必須是無符號整型,其不具有足夠的位有一個良好的PRNG。他們建議使用SVID隨機數函數,其中nrand48_r可能就是您要查找的內容。

或者,您可以使用不同的庫。

+0

如何使用nrand48_r?它似乎不在標準庫中。我可以使用nrand48(&seed),種子是一個短的無符號整數。但是如果我爲每個線程使用不同的種子,我仍然表現不佳 – Eddy

1

在並行執行此類操作時必須考慮的一件事是,由於計算方式不同,可能會有不同的舍入誤差。

實施例:

((A+B) + (C+D))其中(A+B)(C+D)將並行計算可能從串行方法(((A+B) + C) + D)變化。