2011-05-20 39 views
2

我有一個小程序,使用各種卡片計數策略實現了BlackJack的蒙特卡羅模擬。我的主要功能基本上是這樣的:Boost.Thread沒有加速?

int bankroll = 50000; 
int hands = 100; 
int tests = 10000; 
Simulation::strategy = hi_lo; 

for(int i = 0; i < simulations; ++i) 
    runSimulation(bankroll, hands, tests, strategy); 

整個程序在我的機器上運行一個線程大約需要10秒。

我想帶3芯我的處理器已經所以我決定重寫程序,只需執行在單獨的線程的各種戰略這樣的優勢:

int bankroll = 50000; 
int hands = 100; 
int tests = 10000; 
Simulation::strategy = hi_lo; 
boost::thread threads[simulations]; 

for(int i = 0; i < simulations; ++i) 
    threads[i] = boost::thread(boost::bind(runSimulation, bankroll, hands, tests, strategy)); 

for(int i = 0; i < simulations; ++i) 
    threads[i].join(); 

然而,當我跑這個程序,即使我得到了相同的結果,但大約需要24秒才能完成。我在這裏錯過了什麼嗎?

+0

您是否檢查程序是否實際上使用了所有內核? – 2011-05-20 03:34:09

回答

5

如果simulations的值很高,那麼最終會創建大量線程,而這樣做的開銷最終會破壞任何可能的性能增益。

編輯:一種方法,這可能是剛剛啓動三個線程,讓他們每次運行所需的模擬的1/3。或者,使用某種線程池也可以提供幫助。

+0

我以爲同樣的事情。事實上,我的處理器正好有3個內核,所以我試着運行一個循環,每次運行3個線程,並在所有3個循環之前加入,並且沒有發現明顯的改進。我看過我的系統上運行的進程看到,在單線程中只有1個內核被使用,而在所有其他版本中,所有3個內核都被使用,並且仍然沒有加速。沒有一個變量是共享的,因爲它們都是單獨的模擬,並且彼此獨立。 – nrundle 2011-05-20 03:56:45

2

這是一個有線程池的工作隊列的好候選人。我已經使用了Intel Threading Blocks(TBB)來滿足這些要求。也使用手工線程池進行快速入侵。在Windows上,操作系統爲您提供了一個漂亮的線程池支持的工作隊列 "QueueUserWorkItem()"

0

我同意dlev。如果你的函數runSimulation沒有改變下一次調用「runSimulation」所需的任何東西,那麼你可以做類似的事情:

。將「模擬」除以3.

。現在你將有3個計數器「0 to simulation/3」「(simulation/3 + 1)to 2simulation/3」and「(2 * simulation)/ 3 + 1 to simulation」。

所有這3個計數器可以同時用於三個不同的線程。

**注:: **你的要求可能不適合這種類型的檢查在所有的情況下,你所要做的共享數據的鎖止和所有

0

,我遲到了這個晚會,但是要注意,其他兩件事情誰碰到過這樣的帖子:

1)明確地看到第二香草薩特鏈接大衛指出(http://www.drdobbs.com/parallel/eliminate-false-sharing/217500206)。它解決了引起我這個問題的問題,概述了一個結構數據對象包裝器,它確保單獨的並行線程不會競爭總部位於同一內存高速緩存行的資源(硬件控制將阻止多個線程訪問相同的內存高速緩存)線同時)。

2)回答最初的問題,dlev指出了很大一部分問題,但由於這是一個模擬,我敢打賭,有一個更深層次的問題放慢了速度。雖然您的程序的所有高級變量都不共享,但您可能有一個共享的關鍵系統變量:系統級「最後一個隨機數」,它存儲在內部並用於創建下一個隨機數。你甚至可以爲每個模擬初始化專用的發生器對象,但是如果他們正在調用rand()這樣的函數,那麼它們以及它們的線程正在對相同的共享系統資源進行重複調用,然後相互阻塞。

問題#2的解決方案將取決於模擬程序本身的結構。例如,如果對隨機生成器的調用被分割,那麼我可能會批量調入一個預先調用,它將檢索並存儲模擬所需的內容。現在我想知道更復雜的方法來處理潛在的隨機生成共享資源問題...