2011-05-20 46 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的解决方案将取决于模拟程序本身的结构。例如,如果对随机生成器的调用被分割,那么我可能会批量调入一个预先调用,它将检索并存储模拟所需的内容。现在我想知道更复杂的方法来处理潜在的随机生成共享资源问题...