性能权衡 - MATLAB何时比C/C++更好/更慢

59

我知道C/C++是一种更低层次的语言,与其他高级语言相比生成的机器码相对优化。但我想还有很多其他因素,在实践中也能看出来。

当我进行简单的计算,如高斯样本集的蒙特卡罗平均值时,我发现使用C++实现和MATLAB实现没有太大区别,有时事实上MATLAB在时间上表现得更好一些。

当我转向成千上万行代码的大规模仿真时,真正的情况慢慢显现出来。C++仿真显示出明显优势,时间复杂度比MATLAB实现高出100倍。

C++中的代码大部分时间都是串行的,并没有明确做任何高级的优化。然而,据我所知,MATLAB本身就做了很多优化。例如,当我尝试生成大量的随机样本时,这一点就会显现出来,因为使用某些库(如IT++/GSL/Boost)的C++实现相对较慢(所使用的算法相同,即mt19937)。

我的问题很简单,就是想知道MATLAB/C++之间性能上是否有一个更简单的权衡。是否像人们说的那样,“只要可以,就使用C/C++”(经常遇到的)?从不同的角度来看,“除了舒适性,MATLAB还有什么好处?”

顺便说一句,我认为在这里不重要的编码效率参数是显著的,考虑到两种情况下相同的程序员。而且,我认为其他替代方案如Python、R在这里都不相关。但对我们所使用的特定库的依赖应该是有趣的。

[我是通信系统编码理论的博士生。我一直在使用MATLAB/C++进行仿真,并且拥有在这两种情况下编写数万行代码的合理经验]


2
从性能角度来看,如果你知道如何编写Matlab代码,那么Matlab更好;如果你不知道如何编写C++代码,那么C++在其他时间更好。 - RichardPlunkett
3
我已经完成了Matlab到C++的翻译。对于“正常”的Matlab代码,通常期望C++的速度要快20倍。 - RichardPlunkett
@Richard 是的,我忽略了这个方面,只是为了避免太多问题。我相信这个翻译提供了很好的见解。但我主要尝试着关注Matlab和C++的“为什么和何时”。 - Loves Probability
@Richard,“当你知道如何做”的部分,我认为对于普通程序员来说是不常见的,不是吗?如果有人能就这一点提供一些见解,我会很感激,因为它似乎是一个普遍的观点。 - Loves Probability
1
我想提一下MATLAB的优点在于它所有的库都使用相当健壮的实现,因此您不必太担心数值稳定性和选择哪种算法。另一方面,C++库可以提供完全相同的便利... - user904963
2
MATLAB中的许多关键部分都使用某种本地库(内部开发或使用第三方库)实现,并且是用编译语言(C / C ++,Fortran)实现的。例如,简单的反斜杠运算符x = A\b实际上是十几种可能底层实现的前端。对于在纯MATLAB中实现的其他部分,JIT编译器有助于缓解解释语言的成本。此外,MATLAB通常鼓励编写矢量化代码(考虑SIMD指令)。最后,GUI部分主要是用Java实现的。 - Amro
9个回答

129

我已经使用Matlab和C++约10年。对于我的研究实现的每个数值算法,我总是从Matlab原型开始,然后将项目转换为C++,以获得10倍到100倍(我不是开玩笑)的性能提升。当然,我比较的是优化的C++代码和完全向量化的Matlab代码。平均而言,改进约为50倍。

这两种编程语言背后有很多微妙之处,以下是一些误解:

  1. Matlab是一种脚本语言,但C++是编译的

    Matlab使用JIT编译器将您的脚本转换为机器码,使用Matlab提供的编译器可以使速度提高最多1.5倍到2倍。

  2. Matlab代码可能能够被完全向量化,但在C++中必须手动优化代码

    完全向量化的Matlab代码可以调用用C++ / C /汇编编写的库(例如Intel MKL)。但是纯C ++代码可以通过现代编译器合理地进行向量化。

  3. Matlab提供的工具箱和例程应该非常精调,并且应该具有合理的性能

    不是的。除了线性代数例程外,性能通常很差。

您可以通过以下原因将C++的性能提高10倍到100倍:

  1. 在Matlab中调用外部库(MKL)需要时间。

  2. Matlab中的内存是动态分配和释放的。例如,小矩阵乘法:
    A = B * C + D * E + F * G
    需要Matlab创建2个临时矩阵。而在C++中,如果您预先分配内存,则不会创建任何内容。现在想象一下,如果您将该语句循环1000次。C++11 Rvalue引用提供了C ++中的另一种解决方案。这是C ++中最大的改进之一,现在C ++代码可以像纯C代码一样快速。

  3. 如果要进行并行处理,则Matlab模型是多进程,而C ++方式是多线程。如果有许多需要并行化的小任务,则C ++可提供线性增益,直至多个线程,但在Matlab中可能会出现负性能增益。

  4. C++中的向量化涉及使用内部函数/汇编语言,有时只有在C++中才能进行SIMD向量化。

  5. 在C ++中,有经验的程序员有可能完全避免L2高速缓存甚至L1高速缓存未命中,从而将CPU推向其理论吞吐量极限。由于这个原因,Matlab的性能可能落后于C++约10倍。

  6. 在C++中,计算密集型指令有时可以按照其延迟(在汇编或内部函数中小心编码)和依赖性(大多数时间是由编译器或CPU硬件自动完成的)进行分组,以达到理论IPC(每秒时钟周期指令数),并且填充CPU管道。

但是,与Matlab代码相比,C++开发时间也会增加10倍!

以下是使用Mat

B = A(:,2:end)-A(:,1:end-1)

矩阵索引操作使Matlab代码的运行速度比C++代码慢了多倍。是否可以改善矩阵索引的性能?


10
这是一个很好的总结。这让我非常好奇这位来自康奈尔大学的博士到底是谁,但“显然,这个用户更喜欢保持神秘感”。自从我提出这个问题以来已经有两年多了。尊重隐私没有问题。干杯! - Loves Probability
2
谢谢!我非常高兴能够帮助并分享我过去所学到的宝贵经验。 - PhD AP EcE
2
点3.6:最新版本的Matlab不需要复制到第三个矩阵来交换两个矩阵,因为JIT写时复制。命令集:c = a; a = b; b = c; clear c; 只会生成引用,不会发生数据复制。 - Wybird666
@Wybird666:MATLAB一直都有惰性复制(写时复制),这与JIT无关。 - Cris Luengo
关于您的新编辑:是的,这很烦人。但这不是要求更改MATLAB的正确地方,他们不会看到这个。如果您拥有许可证,请直接向MathWorks提交请求。这样做可以更有可能影响他们的工作。祝你好运!(顺便说一句:使用“conv”可以更有效地计算有限差分!) - Cris Luengo
显示剩余8条评论

11

根据我的经验(在两种语言中进行数年的计算机视觉和图像处理),这个问题没有简单的答案,因为Matlab的性能强烈依赖于您的编码风格(比C++性能更加依赖编码风格)。

通常情况下,Matlab包装了经典的基于C++/Fortran的线性代数库。 因此,任何像x = A\b这样的操作都将非常快速。 此外,Matlab在选择这些类型问题的最有效求解器方面做得很好,因此对于x = A\b,Matlab会查看您的矩阵大小并选择适当的低级别例程。

如果您“向量化”代码,即避免使用for循环并使用索引数组或布尔数组来访问数据,则Matlab还可用于大型矩阵的数据操作。 这方面的功能高度优化。

对于其他程序,某些程序是用Matlab编写的,而其他程序则指向C/C++实现(例如Delaunay算法)。 您可以通过键入edit some_routine.m来自行检查这一点。 这将打开代码,并且您将看到它是否全部是Matlab代码,还是仅编译的东西的包装器。

我认为Matlab主要是为了方便 - 但是舒适度将转化为编码时间和最终的金钱,这就是为什么Matlab在工业中使用的原因。 此外,与计算机科学领域的工程师相比,其他领域的工程师只需要很少的编程培训即可轻松学习它。


谢谢你的回答。但是,考虑到Matlab的所有智慧和Fortran级别的优化,为什么Matlab会更慢呢! - Loves Probability
我的意思是,如果你看不到任何改进,那么在汇编级别进行优化不是浪费精力吗? 此外,尽管我理解你的观点,“强烈取决于你的编码风格”需要一些详细说明。我实际上建议考虑在两个方面都具有合理的编程效率,这仍然有100倍的差距。 - Loves Probability
重点是:Matlab在某些大型操作(矩阵和线性代数等低级别操作)方面非常快,但对于其他所有操作则相当慢,因为它本质上是一种解释脚本语言(比其他脚本语言的复杂程度要低得多)。Matlab优化的问题是那些工作量主要集中在大型矩阵和线性代数操作上,周围几乎没有(缓慢的)样板代码。如果您的问题不属于这种类型(即如果您必须使用for循环和非矩阵操作进行编码),则Matlab的速度会下降。 - DCS
1
顺便提一下,Matlab的名字来自“矩阵实验室” - 该产品最初是为了提供一个舒适的界面,以便使用LAPACK和其他软件包中的快速Fortran / C线性代数例程。这就是语言中快速、优化和脚本部分之间的区别所在。 - DCS
我同意DCS的观点 - 一切都取决于你的编码方式。我看到很多用Matlab编写的代码没有利用内置函数,也没有向量化。只要做这两件事情,它就会运行得非常快。如果用C/C++运行代码所节省的总时间超过了编写、测试和验证优化代码所花费的总时间,相比编写、测试和验证良好的Matlab代码所需的时间,我会感到惊讶! - Wybird666

8
作为一名博士研究生,同时也是一个使用Matlab长达10年的用户,我很高兴分享我的观点:
Matlab是一个非常适合开发和原型设计算法的工具,特别是在处理GUI、高级分析(频域、LS优化等)方面:快速编码,强大的语法(想想[]、{}、:等等)。
当你的处理链更加稳定和明确,并且数据维度增加时,请转向C/C++。
主要的Matlab限制出现在考虑其语言类似脚本的时候:只要避免任何循环(使用arrayfun、cellfun或其他矩阵过程),性能就会很高,因为调用的子例程再次在C/C++中。

5

你的问题很难回答。一般而言,C++更快,但如果使用Matlab的精心编写的算法,则可以胜过C ++。在某些情况下,Matlab可以并行化您的代码,而这在许多情况下必须手动完成C ++。 Mathlab可以导出C ++代码。

因此,我的结论是,您必须测量两个程序的性能才能得到答案。但然后,您将比较您的两个实现,而不是Matlab和C ++的一般情况。


5

Matlab在线性代数和数组/矩阵操作方面表现很好,因为它们似乎对底层操作进行了一些额外的优化 - 如果你想超越Matlab,你需要一个类似于优化的BLAS/LAPACK库。

作为一种解释性语言,每当调用Matlab函数时,Matlab会失去时间,由于内部开销,这传统上意味着Matlab循环速度较慢。近年来,JIT编译器有了显著改进(搜索“performance”问题的Matlab SO示例),这在一定程度上缓解了这个问题。由于函数调用开销的影响,所有未在C/C++背后实现的Matlab函数(调用edit functionName查看是否是用Matlab编写的)都可能比C/C++对应函数慢。

最后,Matlab试图友好地对待用户,并可能进行“不必要”的输入检查,这可能需要时间(由于函数调用开销)。例如,如果您知道ismember得到排序的输入,您可以直接调用ismembc(在幕后编译的函数),节省相当多的时间。


4
我认为您至少可以考虑四个方面的差异。
  1. 编译型 vs 解释型
  2. 强类型 vs 动态类型
  3. 性能 vs 快速原型
  4. 特殊优势
1-3容易概括为两个编程语言家族之间的比较。
对于4,MATLAB针对矩阵运算进行了优化。因此,如果您可以在MATLAB中向量化更多代码,则性能可以大大提高。相反,如果需要许多循环,请毫不犹豫地使用C++或创建mex文件。
这毕竟是一个困难的问题。

3
我在从MATLAB切换到C ++后,看到了5.5倍的速度提升。这是用于机器人控制器的 - 大量循环和ode求解。我花了很多时间优化MATLAB代码,几乎没有时间优化C++(我相信再稍微努力一些,它可能会快10倍)。
然而,对于MATLAB代码来说很容易添加GUI,所以我仍然更频繁地使用它。正如其他人所说,首先在MATLAB上进行原型设计很不错。这使得在C ++上实现变得更加简单。

2
除了最终程序的速度之外,你还应该考虑你的代码的总开发时间,即编写和调试的时间等。由于Matlab(及其开源替代品Octave)具有可视化能力,因此可以用于快速原型设计。
如果你使用直接的C++(即没有矩阵库),编写与Matlab代码相当的C++代码可能需要更长的时间(例如,相比花费5分钟编写的Matlab程序,花费10小时编写只比它快10秒的C++代码可能没有意义)。
然而,也有专门的C++矩阵库,如Armadillo,提供类似于Matlab的API。这对于编写性能关键的代码以便从Matlab中调用或将Matlab代码转换为“真实”程序非常有用。

2

一些Matlab代码使用内置多线程的标准线性代数函数。因此,它们似乎比顺序C代码更快。


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