15

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

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

Java vs C# vs C++ 细分

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

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

矩阵乘法比较

这里发生了什么?

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

4

4 回答 4

13

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

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

于 2010-07-12T15:41:25.773 回答
10

为了解释 XNA 矩阵运算很慢的想法的起源:

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

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

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

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

于 2010-07-12T16:20:31.843 回答
7

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

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

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

于 2010-07-12T15:41:35.757 回答
3

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

使用任务并行库 (TPL) 的并行矩阵乘法

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

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

于 2010-07-12T16:19:52.360 回答