C#蒙特卡罗增量风险计算优化,随机数,并行执行。

8

我的当前任务是优化一个蒙特卡罗模拟,该模拟计算一组债务人的区域资本充足率数据。

它目前运行速度太慢了,需要在生产中运行并进行每日多次运行。此外,结果数据的粒度将需要逐步提高到桌面甚至可能是书籍级别,我所得到的代码基本上是业务部门在半生产能力下使用的原型。

该应用程序目前是单线程的,因此我需要将其变为多线程的,可以考虑使用System.Threading.ThreadPool或者Microsoft Parallel Extensions库,但是我在这家银行的服务器上受到.NET 2的限制,所以我可能必须考虑这个人的移植方案,http://www.codeproject.com/KB/cs/aforge_parallel.aspx

我正在尽最大努力让他们升级到.NET 3.5 SP1,但在这样规模的组织中,这可能是一项重大任务,并且可能无法在我的合同时间范围内完成。
我使用dotTracehttp://www.jetbrains.com/profiler)的试用版对应用程序进行了分析。还有哪些好的分析工具?免费的?
执行时间的很大一部分用于生成均匀随机数,然后将其转换为正态分布的随机数。他们使用C# Mersenne twister 实现。我不确定他们是否得到了它,或者这是否是生成均匀随机数的最佳方法(或最佳实现)。然后将其翻译为正态分布版本以供计算使用(我尚未深入研究翻译代码)。
此外,以下内容的使用体验如何?

你知道其他的替代品吗?我是一名C#开发者,所以更喜欢C#,但是用C++封装也不是问题,对吧?

也许使用C++实现会更快。我在想这些库中可能有最快的方法直接生成正态分布随机数,无需转换步骤。此外,它们可能还有一些其他有助于后续计算的函数。

此外,这台电脑是四核Opteron 275,8 GB内存,但运行的是Windows Server 2003 Enterprise 32位。我应该建议他们升级到64位操作系统吗?如果有支持这个决定的文章链接,那真的太感谢了。

总之,非常感谢您提供的任何建议和帮助。


2
你为什么相信增加线程数会改善问题呢? - Eric Lippert
目前代码是单线程运行在一个四核Opteron 275的盒子上。该代码被编写为按顺序运行,编译器、CLR或CPU指令集可以尽最大努力尝试并行运行其中的部分以提高性能。或者我可以编写此代码以在线程并行模型中运行,从而有效地建议CLR、编译器、CPU可以并行运行什么,并让这些低级别的指令优化执行。你有什么想法? - m3ntat
1
8GB的内存在32位系统上只有4GB是浪费的... - Not Sure
有人了解Parallel Extension库吗?有人使用过Microsoft版本的Parallel.For和这个开源版本http://www.codeproject.com/KB/cs/aforge_parallel.aspx吗?我还在寻找对线程非常熟悉的人,以便与.NET线程选项进行比较。因为我是多线程编程的新手。 - m3ntat
4个回答

4
我发现Mersenne Twister非常快。问题可能出在将均匀分布转换为高斯分布的算法(Box-Muller)上。标准算法如下:
y1 = sqrt( - 2 ln(x1) ) cos( 2 pi x2 )
y2 = sqrt( - 2 ln(x1) ) sin( 2 pi x2 )

x1和x2是均匀分布的随机数,y1和y2是高斯分布的输出。

求平方根速度较慢,三角函数更糟糕,并且在接近0时不稳定。关于该主题的Taygeta页面提供了一个更快的方法(伪代码):

         float x1, x2, w, y1, y2;

     do {
             x1 = 2.0 * ranf() - 1.0;
             x2 = 2.0 * ranf() - 1.0;
             w = x1 * x1 + x2 * x2;
     } while ( w >= 1.0 );

     w = sqrt( (-2.0 * ln( w ) ) / w );
     y1 = x1 * w;
     y2 = x2 * w;

如果他们没有使用这样的东西,你可以通过避免三角函数甚至预先生成随机数来加快速度。

作为一条注释,许多现代处理器都有一个汇编指令,可以同时计算正弦和余弦,而且比依次调用两者要便宜得多。据我所知,这不是任何标准库中可用的功能,因为它是处理器特定的功能。 - Not Sure
感谢 @R Ubben,你的提议是否与此 http://en.wikipedia.org/wiki/Box-Muller_transformation 相同,还是另有不同? - m3ntat
是的,它们描述的是极坐标形式。这是拒绝抽样,所以你要扔掉一些数字,但它仍然会快得多。虽然我也在银行工作,但我做这个是为了享受——在光线追踪器中进行全局照明。它确实有所不同。如果速度仍然是一个问题,你可以在每日运行之间离线生成几亿个,取决于运行使用的数量,并根据需要读取它们。然后如果存储用尽就回到生成。 - R Ubben

1

你有没有考虑过在你的代码上使用性能分析器?我曾经见过一些情况,只需进行简单的修复就可以获得非常显著的改进。比如将一些属性切换为字段。


我已经尝试了dottrace的试用版,但结果不够详细。如果RedGate有免费试用版,我会再试一下。 - m3ntat
我认为他们会,Ants已经多次帮我解决了问题。 - Jake Pearson

0

如果你在大规模仿真中使用 .Net,那么一开始就会付出相当大的性能代价...但是话说回来...

如果你运行的是 Mersenne Twister 的纯 C# 实现,很可能你会很难将其所有性能优化。如果你查看 Mersenne Twister 的参考实现,你会发现它们有一个 C 版本,专门为支持 SSE 处理器进行了优化 - 这非常快。我不认为在 C# 中(或者至少我不知道如何)强制使用 SSE 指令以达到这种水平的优化是可能的。我建议在 Mersenne Twister 库周围编写一个 C++/CLI 包装器(或 P/Invoke 包装器),并观察它对性能的影响。然而,你必须小心受到托管-非托管封送造成的性能影响,因为我在这里的其他帖子中看到过关于这个问题的讨论(虽然我现在找不到它们了...)。

我可能因为这样说而引起一些争议,但如果性能是您的应用程序中的一个重要问题,写得好的C或C ++几乎总是比任何托管或解释语言更可取。


2
我其实非常不赞同你最后的声明... C# 可以表现得非常非常好。虽然需要进行性能分析,但是在我的经验中,相比于 C 和 C++ ,进行 C# 的性能分析要容易得多,并且可以通过利用正确的库和了解如何编写紧凑高效的 C# 代码来提高它的性能,甚至可以超越 C 和 C++。 - Reed Copsey
1
我也想有建设性地不同意 :) - peterchen
1
@Reed - 让我澄清一下 - 我说的不是分析的容易程度,也不是可用的工具,也不是优化的难度。我肯定对于任何用解释性或托管语言编写的程序,都可以证明用非托管语言编写一个功能相等且性能相等或更好的程序。 - Not Sure

0

我的经验是,C#与C++的相对性能在很大程度上取决于你正在做什么。这里有一个很好的讨论:

C++ performance vs. Java/C#

对于紧密循环的数学计算(比如向量物理计算),C++比C#快2-3倍,尽管性能可能受到像Sqrt()这样的底层函数的支配。

我采用了混合语言方法,使用C++/OpenMP重新实现最慢的代码,并使用托管的C++/CLI包装器。这使您只需“按需付费”。

这里有一个关于如何使用C++/CLI包装本地C/C++的摘要:

http://msdn.microsoft.com/en-us/library/ms235281.aspx

一旦你掌握了C++/CLI,让事情运行起来就非常容易了。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接