Boost.Thread 没有加速

Boost.Thread no speedup?

本文关键字:加速 Thread Boost      更新时间:2023-10-16

我有一个小程序,它使用各种计数策略实现了二十一点的蒙特卡罗模拟。 我的主要功能基本上是这样做的:

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 秒才能完成。 我在这里错过了什么吗?

如果 simulations 的值很高,那么您最终会创建大量线程,这样做的开销最终可能会破坏任何可能的性能提升。

编辑:一种方法可能是只启动三个线程,让它们各自运行所需模拟的 1/3。或者,使用某种线程池也会有所帮助。

这是一个很好的候选者,适用于具有线程池的工作队列。我已经使用英特尔线程块 (TBB) 来满足此类要求。使用手工制作的线程池也可以快速破解。在Windows上,操作系统为您提供了一个很好的线程池支持的工作队列"队列用户工作项()"

阅读 Herb Sutter 的这些文章。您可能是"虚假共享"的受害者。

http://drdobbs.com/go-parallel/article/showArticle.jhtml?articleID=214100002

http://drdobbs.com/go-parallel/article/showArticle.jhtml?articleID=217500206

我同意 dlev .如果您的函数 runSimulation 没有更改下一次调用 "runSimulation" 正常工作所需的任何内容,那么您可以执行以下操作:

.将"模拟"除以 3。

.现在您将有 3 个计数器"0 到 simulation/3"(simulation/3 + 1) 到 2simulation/3" 和 "(2*simulation)/3 + 1 到 simulation"。

所有这 3 个计数器可以同时在三个不同的线程中使用。

**注意::**您的要求可能根本不适合这种类型的检查,以防您必须进行共享数据锁定和所有

我参加这个聚会迟到了,但想为遇到这篇文章的其他人指出两件事:

1)一定要看到大卫指出的第二个赫伯·萨特链接(http://www.drdobbs.com/parallel/eliminate-false-sharing/217500206)。 它解决了引起我这个问题的问题,概述了一个结构数据对象包装器,该包装器可确保单独的并行线程不会竞争总部设在同一内存缓存行上的资源(硬件控件将阻止多个线程同时访问同一内存缓存行)。

2)对于最初的问题,dlev指出了问题的很大一部分,但由于这是一个模拟,我敢打赌有一个更深层次的问题会减慢速度。 虽然程序的高级变量都没有共享,但您可能有一个共享的关键系统变量:系统级"最后一个随机数",它存储在后台并用于创建下一个随机数。 您甚至可以为每个模拟初始化专用的生成器对象,但如果它们调用像 rand() 这样的函数,那么它们以及扩展它们的线程将重复调用相同的共享系统资源并随后相互阻塞。

问题 #2 的解决方案将取决于模拟程序本身的结构。 例如,如果对随机生成器的调用是零散的,那么我可能会批处理成一个预先调用,该调用检索并存储模拟所需的内容。 这让我现在想知道更复杂的方法来处理潜在的随机生成共享资源问题......