【问题标题】:C# Performance - should I write the computation heavy methods in c++?C# 性能 - 我应该在 C++ 中编写计算繁重的方法吗?
【发布时间】:2011-05-10 21:56:39
【问题描述】:

我正在为一个量化库构建一个原型,该库使用图像处理技术进行一些信号分析。我完全用 C# 构建了初始原型,但性能不如预期。大部分计算是通过繁重的矩阵计算完成的,这些计算占用了大部分时间。

我想知道是否值得为非托管 C++ 代码编写 C++/CLI 接口。有没有人经历过这个?欢迎提出其他优化 C# 性能的建议。

【问题讨论】:

  • 不确定我们能否在不查看某些代码的情况下提供准确的指导。理论上,你可以用 C++ 编写性能更高的代码……但你也可以用 C++ 编写更差的代码。
  • 在您为编写 C++/CLI 代码而烦恼之前,请使用分析器(例如 JetBrains dotTrace、RedGate ANTS 等)找出您的 C# 代码运行缓慢的原因。根据瓶颈,您可能可以通过重新编写一些 C# 代码来删除它,明智地使用 C# 中的 unsafe 关键字和指针,或者在 C++ 中重新编写核心部分。最好的解决方案将取决于瓶颈。请记住,由于编组开销,您最终可能会获得比纯 C++ 解决方案更差的性能。因此,请确保您知道要解决的问题。
  • @Andrew,我想说 C# 通过提供许多开箱即用的解决方案来防止程序员进行更糟糕的编码。将 C# 编码和一些用 C++ 写得很糟糕的代码进行比较是不公平的。
  • @thomas1234- 鉴于这个问题的普遍性,答案是非托管 C++ 会更快。
  • @Jimmy +1 因为我完全同意你的评论;我只是从 C++ 方面更多地看待“让我们将其移至 C++ 以使其更快”的角度。不过,您的评论完成了这个想法。正确编码后,C# 可以更轻松地获得“相当不错的性能”。

标签: c# visual-c++ c++-cli unmanaged heavy-computation


【解决方案1】:

曾经有一段时间用 C/C++ 编写肯定会更好,但现在 C# 优化器和 JIT 非常好,对于纯数学来说,可能没有区别。

当您必须处理内存和可能的数组时,差异就出现了。即便如此,我仍然会使用 C#(或 F#)然后优化热点。 JIT 非常擅长优化小而短暂的对象。

使用数组,您必须担心 C# 会在每次访问时进行边界检查。阅读:

Link

自己测试一下——我一直发现 C# 具有可比性——有时更快。

【讨论】:

  • JIT 无法优化纯数字运算,而且仍然需要处理大量开销。对于某些代码,C# 可能比 C++ 快,但对于数字处理而言,C# 永远不会像经过优化的 C++ 一样快。
  • 我以编写图像处理代码为生,正在进行广泛的性能测试。 C/C++ 总是比 C# 快是不正确的。在 .NET 世界中 C/C++ 有很大的缺点(不能在 Silverlight 和其他安全环境中运行)。当您决定将多线程添加到混合中时,C#/F# 将淘汰 C/C++。
  • @Lou:不知道为什么在最后一部分。为什么 C# 在多线程方面优于 C++? (在性能方面,我基本同意你的看法,可能不值得用 C++ 编写。
  • @Lou,你能举个例子说明 C#.NET 比原生 C++ 运行得更好吗?
  • @Jimmy 最容易解释的是引用计数与垃圾收集——当您使用大量短期小对象时,GC 可以轻松击败引用计数。并非所有 C++ 程序都需要普遍引用计数,但如果您有任何类型的非平凡对象生命周期,您可能会这样做。此外,如果您是从 C# 调用的,则每次跨越托管/非托管边界时都会支付上下文切换惩罚——因此具有繁重 C 后端的 API 不能细化。如果你想要一个丰富的沟通渠道(有很多小调用和回调),上下文切换可以占主导地位。
【解决方案2】:

在这里很难给出明确的答案,但如果性能是一个问题,我会找到一个经过时间考验的库,具有您需要的性能并将其包装起来。

像乘法或除法这样简单的事情在 c++ 和 c# 之间并没有太大区别——c++ 编译器有一个优化器,而 CLR 运行时有一个按需 JITer 来进行优化。所以理论上,c++ 只会在第一次调用时胜过 c#。

但是,理论和实践并不相同。对于更复杂的算法,您还会遇到内存管理器之间的差异以及优化技术的成熟度。如果你想要轶事证据,你可以找到一些math-heavy comparisons here

就我个人而言,我发现在原生库中进行繁重的计算并使用 c++/CLI 调用它会带来很好的提升当计算是最大的瓶颈时。与往常一样,在进行任何优化之前确保是这种情况。

【讨论】:

  • 来这里说这个。有许多非常优化的 C/C++ 库用于信号和图像处理。如果这是瓶颈,那么有人已经为您完成了肮脏的工作。
  • >> 你可以在这里找到一些数学比较重的比较
【解决方案3】:

在我看来,矩阵数学最好在本机代码中完成。甚至 C++ 库通常也允许绑定到较低级别的实现,例如 LAPACK

有一个 C# LAPACK 端口 here(也是同一站点上的 C# BLAS),您可以尝试,但如果这比本机代码更快,我会感到惊讶。

【讨论】:

    【解决方案4】:

    我在 C# 中完成了很多图像处理工作,是的,我通常使用本地代码来处理性能很重要的重型代码,但我只使用了 PInvokes 而不是 C++/CLI 接口。不过,很多时候这不是必需的。

    有很多好的 .NET 分析器。 Red Gate 是我个人的最爱。它可能会帮助您了解瓶颈在哪里。

    【讨论】:

      【解决方案5】:

      唯一合理的语言基准:http://shootout.alioth.debian.org/

      自己看看。

      【讨论】:

        【解决方案6】:

        C# 中的数学计算性能很差。我惊讶地发现 C# 中的数学计算有多慢。只需在 C# 和 C++ 中编写一个循环,其中包含一些乘法、Sin、Cos……,差异是巨大的。

        我不知道托管 C++,但在非托管 C++ 中实现这一切,我想通过 P/Invoke 公开粒度接口应该不会对性能造成什么影响。

        这就是我为繁重的实时图像处理所做的。

        【讨论】:

          【解决方案7】:

          我完全用 C# 构建了初始原型,但性能不如预期。

          那么你有两个选择:

          在 C++ 中构建另一个原型,并查看它的比较或优化您的 C# 代码。无论您使用哪种语言编写代码,在您对其进行分析和优化以及分析和优化之前,您的代码都不会很快。这在 C++ 中尤其如此。如果您用 C# 编写可能最快的实现并将其与 C++ 中可能最快的实现进行比较,那么 C++ 版本很可能会更快。但这会以开发时间为代价。编写高效的 C++ 代码并非易事。如果您是该语言的新手,那么您很可能会编写非常低效的代码,特别是如果您来自 C# 或 Java,它们的工作方式不同,成本也不同。

          如果你只是写一个可以工作的实现,而不用太担心性能,那么我猜 C# 版本可能会更快。

          但这真的取决于你追求什么样的性能(尤其是你需要执行的操作有多昂贵。从托管代码到本机代码的转换会产生开销,所以不值得用于经常执行的短操作。

          C++ 中的数字运算代码可以与 Fortran 中编写的代码一样快(或多或少),但要实现这一点,您需要大量使用高级技术(表达式模板和大量元编程)或一些为您实现它的相当复杂的库。

          值得吗?或者 C# 是否可以快速足够满足您的需求?

          【讨论】:

            【解决方案8】:

            您应该使用 C++ 编写计算量大的程序,通过优化 C# 无法达到接近 C++ 的性能。假设计算需要相当长的时间,调用包装器的开销可以忽略不计。我已经用 C++ 和 C# 编写过代码,并且从未见过任何情况下 .NET 框架代码可以与 C++ 相媲美。在某些情况下,C# 运行得更好,但由于缺乏适当的库或 C++ 中的编码错误,它更好。如果你可以用 C# 和 C++ 编写同样好的代码,我会用 C++ 编写性能代码,其他一切都是 C#。

            如果 x 是世界上最好的 C++ 程序员,而 y 是最好的 C# 程序员,那么大多数时候 x 可以编写比 y 更快的代码。但是,y 在大多数情况下可以比 x 更快地完成编码。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-01-01
              • 1970-01-01
              • 2011-05-22
              • 1970-01-01
              • 1970-01-01
              • 2011-10-09
              相关资源
              最近更新 更多