.NET在数值计算中的速度以我的经验,.NET比原生代码慢2到3倍。(我为多元优化实施了L-BFGS)。我已经关注了stackoverflow上的广告http://www.centerspace.net/products/速度真的很惊人,速度接近nativecode。他们怎么能这样做?他们说:问:NMath是“纯”.NET吗?答:答案在某种程度上取决于您对“纯.NET”的定义。NMath是用C#编写的,外加一个小的托管C++层。但是,NMath确实依赖于本地英特尔数学核心库(包含在NMath中),以便更好地执行基本的线性代数运算。但是没有COM组件,没有DLL——只有.NET程序集。此外,在托管C++层中分配并由本机代码使用的所有内存都是从托管堆中分配的。有人可以向我解释吗?你关于C++/CLI的观点是正确的。为了完成这幅图画,还有两点:他们怎么能这样做?与大多数.NET数字库一样,NMath只不过是嵌入在.NET程序集中的英特尔MKL的包装器,可能通过与C++/CLI链接来创建混合程序集。您可能只是在对实际上不是用.NET编写的位进行基准测试。F#.NET期刊文章数值库:特殊函数、插值和随机数(2008年3月16日)和数值库:线性代数和谱方法(2008年4月16日)测试了很多函数,而NMath实际上是最慢的他们所有的商业图书馆。他们的PRNG比其他人都慢,比免费的Math.NET库慢50%,缺少一些基本功能(例如计算Gamma(-0.5)的能力)和其他基本功能(他们提供的与Gamma相关的功能)坏了。ExtremeOptimization和Bluebit在特征求解器基准测试中都击败了NMath。NMath当时甚至没有提供傅里叶变换。更令人惊讶的是,性能差异有时是巨大的。我们测试的最昂贵的商业数值库(IMSL)在FFT基准测试中比免费的FFTW库慢500多倍,而且当时没有一个库使用超过一个内核。事实上,正是这些库的低质量促使我们将自己的F#商业化为一个数值库(它是100%纯F#代码)。我是ILNumerics的主要开发人员之一。所以我显然有偏见;)但我们会更多地披露我们的内部结构,所以我会深入了解我们的速度“秘密”。这完全取决于系统资源的使用方式!如果您只关心速度并且需要处理大型数组,那么您将确保(按重要性顺序,最重要的优先)妥善管理您的内存!“天真的”内存管理会导致性能不佳,因为它会严重影响GC,导致内存碎片并降低内存局部性(从而降低缓存性能)。在像.NET这样的垃圾收集环境中,这归结为防止频繁的内存分配。在ILNumerics中,我们实现了一个高性能内存池来实现这一点(并确定性地处理临时数组以获得漂亮、舒适的语法,而没有笨拙的函数语义)。利用并行性!这同时针对:线程级并行性和数据级并行性。利用多核计算的计算密集型部分。在X86/X64CPU上,SSE.XX和AVX等SIMD/多媒体扩展允许小型但高效的矢量化。当前的.NET语言不能直接寻址它们。这是MKL可能仍比“纯”.NET代码更快的唯一原因。(但解决方案正在增加。)要达到FORTRAN和C++等高度优化语言的速度,必须对您的代码应用相同的优化。C#提供了执行此操作的选项。请注意,这些注意事项应按顺序进行!如果瓶颈是内存带宽,并且处理器大部分时间都在等待新数据,那么关心SSE扩展甚至绑定检查删除就没有意义。还有,对于很多简单的操作来说,为了最后的小规模达到巅峰性能而付出巨大的努力,甚至是不值得的!考虑LAPACK函数DAXPY的常见示例。它将向量X的元素添加到另一个向量Y的相应元素。如果这是第一次这样做,则必须从主内存中获取X和Y的所有内存。你无能为力。内存是瓶颈!因此,最后一次添加是否在C#中以天真的方式完成(inti=0;i或通过使用矢量化策略)并不重要-它必须等待内存!我知道,这个答案以某种方式“回答”解决了这个问题,因为大多数这些策略目前(还没有?)从上述产品中使用。通过遵循这些要点,您最终将获得比使用“本地”语言的每个简单实现更好的性能。如果您有兴趣,可以透露一下您的L-BFGS实现吗?我很乐意将其转换为ILNumerics并发布比较结果,而且我敢肯定,此处列出的其他库也会随之而来。(?)我发布了一篇博客文章来解决这个问题。关键是C++/CLI。它允许您将C++代码编译为托管.NET程序集。如今,制作混合.Net/本机库以利用这两个平台进行性能优化已成为行业标准。不仅是NMath,许多商业和免费图书馆都有.net接口以这种方式工作。例如:Math.NETNumerics、dnAnalytics、ExtremeOptimization、FinMath等。与MKL的集成在.net数值库中非常流行,并且大多数只使用托管C++程序集作为中间级别。但是这个解决方案有很多缺点:IntelMKL是一个专有软件,有点贵。但是像dnAnalytics这样的库提供了纯.net代码免费替代MKL功能。当然,它要慢得多,但它是免费的且功能齐全。它降低了在32位和64位模式下拥有大量托管C++内核dll所需的兼容性。管理本地调用需要执行编组,这会降低快速调用快速操作(例如Gamma或NormalCDF)的性能。最后两个问题在RTMathFinMath库中得到解决。我真的不知道他们是怎么做到的,但他们提供了纯.netdll,它可以为任何CPU平台编译并支持32位和64位。当我需要数十亿次调用NormalCDF时,我也没有看到对MKL有任何性能影响。由于(本机)英特尔MKL正在计算,您实际上并不是在托管代码中进行计算。您只是在使用.Net的内存管理器,因此.Net代码可以轻松使用结果。我从@DarinDimitrov对他的回答的评论和@TrevorMisfeldt对@Darin的评论的评论中得到了更多评论。因此,将其发布为未来读者的答案。NMath使用P/Invoke或C++/CLI调用英特尔数学核心函数库本机函数,这就是最密集的计算以及速度如此之快的原因。花在英特尔MKL内部分解方法上的时间。也不需要复制数据。所以这不是CLI快不快的问题。这是关于执行发生的地方。@Paul的博客也很棒。这是摘要。C#很快,内存分配不是。重用变量作为ref或out参数,而不是从方法中返回新变量。分配新变量会消耗内存并减慢执行速度。@HaymoKutschbach解释得很好。如果不需要精度,从双精度切换到单精度的性能增益是相当可观的(更不用说数据存储的内存节省了)。对于许多短计算,从C#调用C++/cli例程,将所有指针固定到托管空间中分配的数据,然后调用英特尔库通常比使用P/Invoke从C#直接调用库要好,因为整理的成本数据。正如@HaymoKutschbach在评论中提到的那样,对于blittable类型,C++/CLI和C#之间没有区别。blittable类型的数组和仅包含blittable成员的类是固定的,而不是在编组期间复制。请参阅https://msdn.microsoft.com/en-us/library/75dwhxf7(v=vs.110).aspx以获取blittable和非blittable类型的列表。以上就是《C#学习教程:.NETSpeedinNumericalComputing》的全部内容。如果对你有用,需要了解更多C#学习教程,希望大家多多关注---本文收集自网络,不代表立场,如涉及侵权,请点击右边联系管理员删除。如需转载请注明出处:
