【问题标题】:Why is matrix multiplication in .NET so slow?为什么.NET中的矩阵乘法这么慢?
【发布时间】:2011-03-14 20:29:22
【问题描述】:

我不太明白是什么让 C#/.NET(甚至 Java)中的矩阵乘法如此缓慢。

看看这个基准(source):试图找到一个更新的基准。

C# 的整数和双精度性能非常接近使用 MSVC++ 编译的 C++。双精度的 87% 和 32 位整数的 99%。相当不错,我会说。但是再看看矩阵乘法。差距扩大到 C# 的速度大约是 19%。这是一个相当大的差异,我不明白。矩阵乘法只是一堆简单的数学运算。怎么变得这么慢?它不应该与等量的简单浮点或整数运算大致一样快吗?

这对于游戏和 XNA 来说尤其值得关注,其中矩阵和矢量性能对于物理引擎等事物至关重要。前段时间,Mono 通过一些漂亮的向量和矩阵类增加了对 SIMD 指令的支持。它缩小了差距,使 Mono 比手写 C++ 更快,尽管不如带有 SIMD 的 C++ 快。 (source)

这是怎么回事?

编辑:仔细看,我误读了第二张图。 C# 看起来非常接近。 第一个基准测试只是做错了什么吗?抱歉,我错过了第一个基准测试的版本号。我把它作为我一直听到的“C# 线性代数很慢”的方便参考。我会尝试再找一个。

【问题讨论】:

  • C# 版本 + 选项:.Net Framework 1.1.4322 呃...没有更新的版本吗?
  • 坐着等着看 JonSkeet 对此事的看法 :-)
  • 测试是用 VS 2003 完成的。(注意 C++ 版本也是如此。)因此是 .net 的古老版本。
  • @GalacticJello 是的,但即使如此,为什么它比整数/浮点运算慢得多?我会看看能不能找到更多的基准。
  • @Matt Olenick:那是 .NET 的第一个(嗯……第二个)版本。此外,XNA 甚至不能在 .NET 1.1 上运行,它是 .NET 2.0 精简版的实现。信不信由你,在早期版本之后,语言得到了改进。

标签: c# .net performance xna matrix-multiplication


【解决方案1】:

这是处理矩阵乘法的更新基准(以及一些使用新任务并行库的基准):

Parallel Matrix Multiplication with the Task Parallel Library (TPL)

文章介绍了不同的方法,并解释了为什么多维数组是一个糟糕的选择:

做矩阵最简单的方法 乘法是使用 .NET 具有 i,j,k 的多维数组 在循环中排序。问题 是双重的。首先,i,j.k 排序 以忙碌的方式访问内存 导致不同位置的数据 拉进去。其次,它使用的是 多维数组。是的,.NET 多维数组很方便, 但是速度很慢。

【讨论】:

    【解决方案2】:

    解释XNA矩阵运算慢的想法的由来:

    首先是初学者级别的问题:XNA Matrix 类的 operator* 将制作多个副本。这比您对等效 C++ 代码的预期要慢。

    (当然,如果你使用Matrix.Multiply(),那么你可以通过引用传递。)

    第二个原因是 XNA 在 Xbox 360 上使用的 .NET Compact Framework 无法访问原生 C++ 游戏可用的 VMX 硬件 (SIMD)。

    这就是为什么你总是听说它很慢,至少。正如您从发布的基准中看到的那样 - 当您将苹果与苹果进行比较时,它并不是真的那么“慢”。

    【讨论】:

    • 这是有道理的。也许一些误解来自使用运算符。
    【解决方案3】:

    很明显,基准测试作者没有理解 C# 中锯齿状数组和多维数组之间的区别。这真的不是一个苹果对苹果的比较。当我将代码更改为使用锯齿状数组而不是多维数组以便它以更类似于 Java 的方式运行时,C# 代码最终运行速度是 Java 的两倍……使其比 Java 更快(虽然只是勉强,这可能是统计上不显着)。在 C# 中,多维数组速度较慢,因为在查找数组槽时涉及到额外的工作,并且因为它们无法消除数组边界检查......但是。

    请参阅此question,以更深入地分析为什么多维数组比锯齿状数组慢。

    有关数组边界检查的更多信息,请参阅blog。文章特别警告不要使用多维数组进行矩阵乘法。

    【讨论】:

      【解决方案4】:

      对于像这样的大型矩阵,CPU 缓存成为限制因素。最重要的是矩阵的存储方式。基准代码是比较苹果和橘子。 C++代码使用交错数组,C#代码使用二维数组。

      重写 C# 代码以使用锯齿状数组也使其速度提高了一倍。重写矩阵乘法代码以避免数组索引边界检查似乎没有意义,没有人会使用这样的代码来解决实际问题。

      【讨论】:

      • 谢谢,这一切都清楚了。那么为什么我总是听到(以及其他原因)“XNA 很慢,因为 C# 中的矩阵乘法很慢”?这不是真的吗?
      • 我不知道,从我坐的地方来看,这是一个无法证实的说法。 XNA 程序员是否经常编写自己的矩阵乘法代码? C/C++ 代码在速度方面毫不妥协,当它爆炸时,你会从耳朵里捡起弹片。如果 C# 中的特定算法存在速度问题,那么您始终可以使用 C/C++。
      • 不,他们使用 XNA 提供的库。
      猜你喜欢
      • 2012-07-14
      • 1970-01-01
      • 2012-06-22
      • 2016-11-04
      • 2012-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多