我的任务是进行现有的单线程蒙特卡洛仿真并对其进行优化。这是一个ac#控制台应用程序,没有数据库访问权限,它只能从csv文件加载一次数据并将其写到末尾,因此它几乎只受CPU限制,也仅使用约50mb的内存。
我已经通过Jetbrains dotTrace分析器运行它。在总执行时间中,约30%会生成统一随机数,而24%会将统一随机数转换为正态分布的随机数。
基本算法是大量嵌套的for循环,中心是随机数调用和矩阵乘法,每次迭代都返回一个double,并将其添加到结果列表中,对该列表进行定期排序并测试某些收敛标准(在检查时如果总迭代次数的5%计入点数)(如果可接受),则程序会跳出循环并写入结果,否则将继续执行。
我希望开发人员可以考虑:
由于我从未编写过任何并行或多线程代码,因此最欢迎上面教程的一些链接。
当前的应用需要2个小时进行500,000次迭代,业务需要将其扩展到3,000,000次迭代,并且每天需要多次调用,因此需要进行一些优化。
特别希望听到使用Microsoft Parallels Extension或AForge.Net Parallel的人的来信
这需要相当快地投入生产,因此即使我知道并入了并发库,.net 4 beta也要发布了,一旦发布,我们可以考虑稍后迁移到.net 4。目前服务器具有.Net 2,我已将开发箱中的.net 3.5 SP1升级提交审核。
谢谢
更新资料
我刚刚尝试了Parallel.For实现,但是它带来了一些奇怪的结果。单线程:
IRandomGenerator rnd = new MersenneTwister();
IDistribution dist = new DiscreteNormalDistribution(discreteNormalDistributionSize);
List<double> results = new List<double>();
for (int i = 0; i < CHECKPOINTS; i++)
{
results.AddRange(Oblist.Simulate(rnd, dist, n));
}
至:
Parallel.For(0, CHECKPOINTS, i =>
{
results.AddRange(Oblist.Simulate(rnd, dist, n));
});
在Simulation内,有许多对rnd.nextUniform()的调用,我想我得到了很多相同的值,这是否有可能发生,因为现在是并行的?
也可能List AddRange调用的问题不是线程安全的吗?我看到这个
System.Threading.Collections.BlockingCollection可能值得使用,但是它只有一个Add方法而没有AddRange,因此我不得不查看结果并以线程安全的方式添加。任何使用Parallel的人的见解。我切换到System.Random为我的电话暂时因为我与我的梅森难题实现调用nextUniform时,得到了一个例外,也许它不是线程安全的一个特定阵列得到一个索引越界....
首先,您需要了解为什么您认为使用多个线程是一种优化-实际上并非如此。仅当您拥有多个处理器时,使用多个线程才能使工作负载更快地完成,然后使可用CPU的速度最多快上很多倍(这称为加速)。传统意义上的工作不是“优化”的(即工作量没有减少-实际上,使用多线程,由于线程开销,工作量通常会增加)。
因此,在设计应用程序时,您必须找到可以并行或重叠方式完成的工作。可以并行生成随机数(通过在不同的CPU上运行多个RNG),但是随着获得不同的随机数,这也会改变结果。另一种选择是在一个CPU上生成随机数,在其他CPU上生成其他所有内容。由于RNG仍将按顺序运行,并且仍承担30%的负载,因此最高可提速3。
因此,如果要进行并行化,最终将有3个线程:线程1运行RNG,线程2产生正态分布,线程3执行其余的模拟。
对于这种架构,生产者-消费者架构是最合适的。每个线程将从队列中读取其输入,并将其输出生成另一个队列。每个队列都应该阻塞,因此如果RNG线程落后,则规范化线程将自动阻塞,直到有新的随机数可用为止。为了提高效率,我会跨线程传递100个(或更大)数组中的随机数,以避免每个随机数上的同步。
对于这种方法,您不需要任何高级线程。只需使用常规线程类,没有池,没有库。您唯一需要的(不幸的是)不在标准库中是阻塞的Queue类(System.Collections中的Queue类不好)。Codeproject提供了一个合理的外观实现;可能还有其他。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句