MATLAB OOP 速度慢还是我做错了什么? [英] Is MATLAB OOP slow or am I doing something wrong?

查看:28
本文介绍了MATLAB OOP 速度慢还是我做错了什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在试验 MATLAB OOP,一开始我模仿了我的 C++ 的 Logger 类,我将所有的字符串辅助函数放在一个 String 类中,认为这会很棒能够执行诸如 a + ba == ba.find( b ) 之类的事情strcat( ab ), strcmp( a, b ), 检索strfind( a, b )的第一个元素等

问题:减速

我使用了上述东西,并立即注意到急剧放缓.是我做错了(这当然是可能的,因为我的 MATLAB 经验相当有限),还是 MATLAB 的 OOP 只是引入了很多开销?

我的测试用例

这是我对字符串所做的简单测试,基本上只是附加一个字符串并再次删除附加部分:

<块引用>

注意:不要在实际代码中实际编写这样的 String 类!Matlab 现在有一个原生的 string 数组类型,你应该改用它.

classdef String <处理....特性stringobj = '';结尾函数 o = plus( o, b )o.stringobj = [o.stringobj b];结尾函数 n = 长度( o )n = 长度(o.stringobj);结尾函数 o = SetLength( o, n )o.stringobj = o.stringobj( 1 : n );结尾结尾函数 atest( a, b ) % 普通函数n = 长度( a );a = [ a b ];a = a( 1 : n );函数 btest( a, b ) %OOPn = a.Length();a = a + b;a.SetLength(n);函数 RunProfilerLoop( nLoop, fun, varargin )简介;对于 i = 1 :nLoop乐趣(可变参数{:});结尾配置文件关闭;简介报告;a = '测试';aString = String('测试');RunProfilerLoop( 1000, @(x,y)atest(x,y), a, 'appendme' );RunProfilerLoop( 1000, @(x,y)btest(x,y), aString, 'appendme' );

结果

1000 次迭代的总时间(以秒为单位):

<块引用>

btest 0.550(String.SetLength 0.138,String.plus 0.065,String.Length 0.057)

测试 0.015

记录器系统的结果同样是:1000 次调用需要 0.1 秒到 frpintf( 1, 'test ' ), 在内部使用 String 类时对我的系统进行 1000 次调用需要 7 (!) 秒(好吧,它有更多的逻辑,但是为了与 C++ 比较:我的系统在输出端使用 std::string( "blah" )std::cout 与普通 std 的开销::cout <<blah" 大约为 1 毫秒.)

是否只是查找类/包函数时的开销?

由于 MATLAB 被解释,它必须在运行时查找函数/对象的定义.所以我想知道在查找类或包函数与路径中的函数时可能会涉及更多的开销.我试图对此进行测试,但它变得更奇怪了.为了排除类/对象的影响,我比较了在路径中调用函数与在包中调用函数:

function n = atest( x, y )n = ctest( x, y );% ctest 在 matlab 路径中函数 n = btest( x, y )n = util.ctest( x, y );% ctest 在 +util 目录中,父目录在 path 中

结果,收集方式同上:

<块引用>

测试 0.004 秒,ctest 0.001 秒

btest 0.060 秒,util.ctest 中的 0.014 秒

那么,所有这些开销是否只是来自 MATLAB 花费时间查找其 OOP 实现的定义,而这些开销并不存在于直接位于路径中的函数?

解决方案

我使用 OO MATLAB 已经有一段时间了,最​​终发现了类似的性能问题.

简短的回答是:是的,MATLAB 的 OOP 有点慢.有大量的方法调用开销,高于主流的 OO 语言,而且你无能为力.部分原因可能是惯用的 MATLAB 使用向量化"减少方法调用次数的代码,每次调用的开销不是高优先级.

我通过编写什么都不做的nop"来对性能进行基准测试.函数作为各种类型的函数和方法.以下是一些典型的结果.

<前>>> call_nops计算机:PCWIN 版本:2009b调用每个函数/方法 100000 次nop() 函数:每次调用 0.02261 秒 0.23 微秒nop1-5() 函数:每次调用 0.02182 秒 0.22 微秒nop() 子函数:每次调用 0.02244 秒 0.22 微秒@()[] 匿名函数:每次调用 0.08461 秒 0.85 微秒nop(obj) 方法:每次调用 0.24664 秒 2.47 微秒nop1-5(obj) 方法:每次调用 0.23469 秒 2.35 微秒nop() 私有函数:每次调用 0.02197 秒 0.22 微秒classdef nop(obj):每次调用 0.90547 秒 9.05 微秒classdef obj.nop():每次调用 1.75522 秒 17.55 微秒classdef private_nop(obj): 0.84738 sec 8.47 usec per callclassdef nop(obj) (m-file): 0.90560 sec 9.06 usec per callclassdef class.staticnop():每次调用 1.16361 sec 11.64 usecJava nop():每次调用 2.43035 秒 24.30 微秒Java static_nop():每次调用 0.87682 秒 8.77 微秒Java nop() 来自 Java:0.00014 sec 0.00 usec per callMEX mexnop():每次调用 0.11409 秒 1.14 微秒C nop(): 0.00001 sec 0.00 usec per call

R2008a 到 R2009b 的类似结果.这是在运行 32 位 MATLAB 的 Windows XP x64 上.

Java nop()"是一个从 M 代码循环内调用的无操作 Java 方法,包括每次调用的 MATLAB 到 Java 调度开销.来自 Java 的 Java nop()"与 Java for() 循环中调用的内容相同,并且不会产生边界惩罚.对 Java 和 C 的计时持保留态度;一个聪明的编译器可以完全优化调用.

包作用域机制是新的,大约与 classdef 类同时引入.它的行为可能与此有关.

一些初步结论:

  • 方法比函数慢.
  • 新样式 (classdef) 方法比旧样式方法慢.
  • 新的 obj.nop() 语法比 nop(obj) 语法慢,即使对于 classdef 对象上的相同方法也是如此.Java 对象(未显示)也是如此.如果你想快点,调用 nop(obj).
  • 在 Windows 上的 64 位 MATLAB 中,方法调用开销更高(大约 2 倍).(未显示.)
  • MATLAB 方法调度比其他一些语言慢.

说为什么会这样只是我的猜测.MATLAB 引擎的 OO 内部结构不是公开的.这本身不是解释与编译的问题——MATLAB 有一个 JIT——但 MATLAB 更松散的类型和语法可能意味着在运行时需要更多的工作.(例如,仅凭语法无法判断f(x)"是函数调用还是数组索引;这取决于运行时工作区的状态.)这可能是因为 MATLAB 的类定义以许多其他语言所没有的方式与文件系统状态相关联.

那么,该怎么办?

对此的惯用 MATLAB 方法是矢量化"通过构造类定义使对象实例包装数组来编写代码;也就是说,它的每个字段都包含并行数组(在 MATLAB 文档中称为平面"组织).与其拥有一个对象数组,每个对象的字段都包含标量值,不如定义本身就是数组的对象,并让方法将数组作为输入,并对字段和输入进行矢量化调用.这减少了方法调用的次数,希望足以使调度开销不会成为瓶颈.

在 MATLAB 中模仿 C++ 或 Java 类可能不是最佳选择.Java/C++ 类通常构建为对象是最小的构建块,尽可能具体(即,许多不同的类),您将它们组合成数组、集合对象等,并使用循环对它们进行迭代.要创建快速的 MATLAB 类,请彻底改变这种方法.拥有字段为数组的更大类,并在这些数组上调用向量化方法.

重点是安排您的代码以发挥语言的优势 - 数组处理、矢量化数学 - 并避免弱点.

自原帖以来,R2010b 和 R2011a 已经问世.总体情况是一样的,MCOS 调用变得更快,而 Java 和旧式方法调用变得更慢.

我曾经在这里有一些关于路径敏感性"的注释.有一个额外的函数调用时序表,其中函数时间受 Matlab 路径配置方式的影响,但这似乎是我当时特定网络设置的异常.上面的图表反映了我的测试在一段时间内占优势的典型时间.

更新:R2011b

编辑 (2/13/2012):R2011b 已经过时,性能图片已经改变到足以更新这个.

<前>Arch:PCWIN 版本:2011b机器:R2011b,Windows XP,8x Core i7-2600 @ 3.40GHz,3 GB RAM,NVIDIA NVS 300每个操作做100000次每次调用样式总微秒nop() 函数:0.01578 0.16nop(), 10x 循环展开:0.01477 0.15nop(), 100x 循环展开:0.01518 0.15nop() 子函数:0.01559 0.16@()[] 匿名函数:0.06400 0.64nop(obj) 方法:0.28482 2.85nop() 私有函数:0.01505 0.15classdef nop(obj): 0.43323 4.33classdef obj.nop(): 0.81087 8.11classdef private_nop(obj): 0.32272 3.23classdef class.staticnop(): 0.88959 8.90类定义常量:1.51890 15.19类定义属性:0.12992 1.30带有 getter 的 classdef 属性:1.39912 13.99+pkg.nop() 函数:0.87345 8.73+pkg.nop() 从内部 +pkg: 0.80501 8.05Java obj.nop(): 1.86378 18.64Java nop(obj): 0.22645 2.26Java feval('nop',obj): 0.52544 5.25Java Klass.static_nop():0.35357 3.54来自 Java 的 Java obj.nop():0.00010 0.00MEX mexnop(): 0.08709 0.87C nop(): 0.00001 0.00j()(内置):0.00251 0.03

我认为这样做的结果是:

  • MCOS/classdef 方法更快.只要您使用 foo(obj) 语法,成本现在与旧样式类相当.因此,在大多数情况下,方法速度不再是坚持使用旧样式类的理由.(荣誉,MathWorks!)
  • 将函数放入命名空间会使它们变慢.(不是 R2011b 中的新内容,只是我测试中的新内容.)

更新:R2014a

我重构了基准测试代码并在 R2014a 上运行.

<前>PCWIN64上的Matlab R2014aMatlab 8.3.0.532 (R2014a)/Java 1.7.0_11 在 PCWIN64 Windows 7 6.1 (eilonwy-win7)机器:Core i7-3615QM CPU @ 2.30GHz,4 GB RAM(VMware 虚拟平台)nIters = 100000操作时间(微秒)nop() 函数:0.14nop() 子函数:0.14@()[] 匿名函数:0.69nop(obj) 方法:3.28@class 上的 nop() 私有 fcn:0.14类定义 nop(obj): 5.30classdef obj.nop(): 10.78classdef pivate_nop(obj): 4.88classdef class.static_nop(): 11.81类定义常量:4.18classdef 属性:1.18带有 getter 的 classdef 属性:19.26+pkg.nop() 函数:4.03+pkg.nop() 从内部 +pkg: 4.16feval('nop'): 2.31feval(@nop): 0.22评估('nop'):59.46Java obj.nop(): 26.07Java nop(对象):3.72Java feval('nop',obj): 9.25Java Klass.staticNop(): 10.54来自 Java 的 Java obj.nop():0.01MEX mexnop(): 0.91内置 j(): 0.02struct s.foo 字段访问:0.14空闲(持久):0.00

更新:R2015b:对象变得更快!

这是 R2015b 结果,由 @Shaked 友情提供.这是一个变化:OOP明显更快,现在obj.method()语法和method(obj)一样快,并且比传统的 OOP 对象快得多.

<前>PCWIN64上的Matlab R2015bMatlab 8.6.0.267246 (R2015b)/Java 1.7.0_60 on PCWIN64 Windows 8 6.2 (nanit-shaked)机器:Core i7-4720HQ CPU @ 2.60GHz,16 GB RAM (20378)nIters = 100000操作时间(微秒)nop() 函数:0.04nop() 子函数:0.08@()[] 匿名函数:1.83nop(obj) 方法:3.15@class 上的 nop() 私有 fcn:0.04类定义 nop(obj): 0.28classdef obj.nop(): 0.31classdef pivate_nop(obj): 0.34classdef class.static_nop(): 0.05类定义常量:0.25classdef 属性:0.25带 getter 的 classdef 属性:0.64+pkg.nop() 函数:0.04+pkg.nop() 从内部 +pkg: 0.04feval('nop'): 8.26feval(@nop): 0.63评估('nop'):21.22Java obj.nop(): 14.15Java nop(obj): 2.50Java feval('nop',obj): 10.30Java Klass.staticNop(): 24.48来自 Java 的 Java obj.nop():0.01MEX mexnop(): 0.33内置 j(): 0.15struct s.foo 字段访问:0.25空闲(持久):0.13

更新:R2018a

这是 R2018a 的结果.这不是我们在 R2015b 中引入新执行引擎时看到的巨大飞跃,但它仍然是一个可观的逐年改进.值得注意的是,匿名函数句柄变得更快了.

<前>MACI64 上的 Matlab R2018aMatlab 9.4.0.813654 (R2018a)/Java 1.8.0_144 在 MACI64 Mac OS X 10.13.5 (eilonwy)机器:Core i7-3615QM CPU @ 2.30GHz,16 GB RAMnIters = 100000操作时间(微秒)nop() 函数:0.03nop() 子函数:0.04@()[] 匿名函数:0.16类定义 nop(obj): 0.16classdef obj.nop(): 0.17classdef pivate_nop(obj): 0.16classdef class.static_nop(): 0.03类定义常量:0.16classdef 属性:0.13带 getter 的 classdef 属性:0.39+pkg.nop() 函数:0.02+pkg.nop() 从内部 +pkg: 0.02feval('nop'): 15.62feval(@nop): 0.43评估('nop'):32.08Java obj.nop(): 28.77Java nop(对象):8.02Java feval('nop',obj): 21.85Java Klass.staticNop(): 45.49来自 Java 的 Java obj.nop():0.03MEX mexnop(): 3.54内置 j(): 0.10struct s.foo 字段访问:0.16空闲(持久):0.07

更新:R2018b 和 R2019a:无变化

没有重大变化.我不想把测试结果包括在内.

更新:R2021a:更快的物体!

看起来 classdef 对象又变得明显更快了.但是结构变得更慢了.

<前>MACI64 上的 Matlab R2021aMatlab 9.10.0.1669831 (R2021a) Update 2/Java 1.8.0_202 on MACI64 Mac OS X 10.14.6 (eilonwy)机器:Core i7-3615QM CPU @ 2.30GHz,4 核,16 GB RAMnIters = 100000操作时间(微秒)nop() 函数:0.03nop() 子函数:0.04@()[] 匿名函数:0.14nop(obj) 方法:6.65@class 上的 nop() 私有 fcn:0.02类定义 nop(obj): 0.03classdef obj.nop(): 0.04classdef pivate_nop(obj): 0.03classdef class.static_nop(): 0.03类定义常量:0.16classdef 属性:0.12带有 getter 的 classdef 属性:0.17+pkg.nop() 函数:0.02+pkg.nop() 从内部 +pkg: 0.02feval('nop'): 14.45feval(@nop): 0.59评估('nop'):23.59Java obj.nop(): 30.01Java nop(对象):6.80Java feval('nop',obj): 18.17Java Klass.staticNop(): 16.77来自 Java 的 Java obj.nop():0.02MEX mexnop(): 2.51内置 j(): 0.21struct s.foo 字段访问:0.29空闲(持久):0.26

基准测试的源代码

我已将这些基准测试的源代码放在 GitHub 上,并在 MIT 许可下发布.https://github.com/apjanke/matlab-bench

I'm experimenting with MATLAB OOP, as a start I mimicked my C++'s Logger classes and I'm putting all my string helper functions in a String class, thinking it would be great to be able to do things like a + b, a == b, a.find( b ) instead of strcat( a b ), strcmp( a, b ), retrieve first element of strfind( a, b ), etc.

The problem: slowdown

I put the above things to use and immediately noticed a drastic slowdown. Am I doing it wrong (which is certainly possible as I have rather limited MATLAB experience), or does MATLAB's OOP just introduce a lot of overhead?

My test case

Here's the simple test I did for string, basically just appending a string and removing the appended part again:

Note: Don't actually write a String class like this in real code! Matlab has a native string array type now, and you should use that instead.

classdef String < handle
  ....
  properties
    stringobj = '';
  end
  function o = plus( o, b )
    o.stringobj = [ o.stringobj b ];
  end
  function n = Length( o )
    n = length( o.stringobj );
  end
  function o = SetLength( o, n )
    o.stringobj = o.stringobj( 1 : n );
  end
end

function atest( a, b ) %plain functions
  n = length( a );
  a = [ a b ];
  a = a( 1 : n );

function btest( a, b ) %OOP
  n = a.Length();
  a = a + b;
  a.SetLength( n );

function RunProfilerLoop( nLoop, fun, varargin )
  profile on;
  for i = 1 : nLoop
    fun( varargin{ : } );
  end
  profile off;
  profile report;

a = 'test';
aString = String( 'test' );
RunProfilerLoop( 1000, @(x,y)atest(x,y), a, 'appendme' );
RunProfilerLoop( 1000, @(x,y)btest(x,y), aString, 'appendme' );

The results

Total time in seconds, for 1000 iterations:

btest 0.550 (with String.SetLength 0.138, String.plus 0.065, String.Length 0.057)

atest 0.015

Results for the logger system are likewise: 0.1 seconds for 1000 calls to frpintf( 1, 'test ' ), 7 (!) seconds for 1000 calls to my system when using the String class internally (OK, it has a lot more logic in it, but to compare with C++: the overhead of my system that uses std::string( "blah" ) and std::cout at the output side vs plain std::cout << "blah" is on the order of 1 millisecond.)

Is it just overhead when looking up class/package functions?

Since MATLAB is interpreted, it has to look up the definition of a function/object at run time. So I was wondering that maybe much more overhead is involved in looking up class or package function vs functions that are in the path. I tried to test this, and it just gets stranger. To rule out the influence of classes/objects, I compared calling a function in the path vs a function in a package:

function n = atest( x, y )
  n = ctest( x, y ); % ctest is in matlab path

function n = btest( x, y )
  n = util.ctest( x, y ); % ctest is in +util directory, parent directory is in path

Results, gathered same way as above:

atest 0.004 sec, 0.001 sec in ctest

btest 0.060 sec, 0.014 sec in util.ctest

So, is all this overhead just coming from MATLAB spending time looking up definitions for its OOP implementation, whereas this overhead is not there for functions that are directly in the path?

解决方案

I've been working with OO MATLAB for a while, and ended up looking at similar performance issues.

The short answer is: yes, MATLAB's OOP is kind of slow. There is substantial method call overhead, higher than mainstream OO languages, and there's not much you can do about it. Part of the reason may be that idiomatic MATLAB uses "vectorized" code to reduce the number of method calls, and per-call overhead is not a high priority.

I benchmarked the performance by writing do-nothing "nop" functions as the various types of functions and methods. Here are some typical results.

>> call_nops
Computer: PCWIN   Release: 2009b
Calling each function/method 100000 times
nop() function:                 0.02261 sec   0.23 usec per call
nop1-5() functions:             0.02182 sec   0.22 usec per call
nop() subfunction:              0.02244 sec   0.22 usec per call
@()[] anonymous function:       0.08461 sec   0.85 usec per call
nop(obj) method:                0.24664 sec   2.47 usec per call
nop1-5(obj) methods:            0.23469 sec   2.35 usec per call
nop() private function:         0.02197 sec   0.22 usec per call
classdef nop(obj):              0.90547 sec   9.05 usec per call
classdef obj.nop():             1.75522 sec  17.55 usec per call
classdef private_nop(obj):      0.84738 sec   8.47 usec per call
classdef nop(obj) (m-file):     0.90560 sec   9.06 usec per call
classdef class.staticnop():     1.16361 sec  11.64 usec per call
Java nop():                     2.43035 sec  24.30 usec per call
Java static_nop():              0.87682 sec   8.77 usec per call
Java nop() from Java:           0.00014 sec   0.00 usec per call
MEX mexnop():                   0.11409 sec   1.14 usec per call
C nop():                        0.00001 sec   0.00 usec per call

Similar results on R2008a through R2009b. This is on Windows XP x64 running 32-bit MATLAB.

The "Java nop()" is a do-nothing Java method called from within an M-code loop, and includes the MATLAB-to-Java dispatch overhead with each call. "Java nop() from Java" is the same thing called in a Java for() loop and doesn't incur that boundary penalty. Take the Java and C timings with a grain of salt; a clever compiler could optimize the calls away completely.

The package scoping mechanism is new, introduced at about the same time as the classdef classes. Its behavior may be related.

A few tentative conclusions:

  • Methods are slower than functions.
  • New style (classdef) methods are slower than old style methods.
  • The new obj.nop() syntax is slower than the nop(obj) syntax, even for the same method on a classdef object. Same for Java objects (not shown). If you want to go fast, call nop(obj).
  • Method call overhead is higher (about 2x) in 64-bit MATLAB on Windows. (Not shown.)
  • MATLAB method dispatch is slower than some other languages.

Saying why this is so would just be speculation on my part. The MATLAB engine's OO internals aren't public. It's not an interpreted vs compiled issue per se - MATLAB has a JIT - but MATLAB's looser typing and syntax may mean more work at run time. (E.g. you can't tell from syntax alone whether "f(x)" is a function call or an index into an array; it depends on the state of the workspace at run time.) It may be because MATLAB's class definitions are tied to filesystem state in a way that many other languages' are not.

So, what to do?

An idiomatic MATLAB approach to this is to "vectorize" your code by structuring your class definitions such that an object instance wraps an array; that is, each of its fields hold parallel arrays (called "planar" organization in the MATLAB documentation). Rather than having an array of objects, each with fields holding scalar values, define objects which are themselves arrays, and have the methods take arrays as inputs, and make vectorized calls on the fields and inputs. This reduces the number of method calls made, hopefully enough that the dispatch overhead is not a bottleneck.

Mimicking a C++ or Java class in MATLAB probably won't be optimal. Java/C++ classes are typically built such that objects are the smallest building blocks, as specific as you can (that is, lots of different classes), and you compose them in arrays, collection objects, etc, and iterate over them with loops. To make fast MATLAB classes, turn that approach inside out. Have larger classes whose fields are arrays, and call vectorized methods on those arrays.

The point is to arrange your code to play to the strengths of the language - array handling, vectorized math - and avoid the weak spots.

EDIT: Since the original post, R2010b and R2011a have come out. The overall picture is the same, with MCOS calls getting a bit faster, and Java and old-style method calls getting slower.

EDIT: I used to have some notes here on "path sensitivity" with an additional table of function call timings, where function times were affected by how the Matlab path was configured, but that appears to have been an aberration of my particular network setup at the time. The chart above reflects the times typical of the preponderance of my tests over time.

Update: R2011b

EDIT (2/13/2012): R2011b is out, and the performance picture has changed enough to update this.

Arch: PCWIN   Release: 2011b 
Machine: R2011b, Windows XP, 8x Core i7-2600 @ 3.40GHz, 3 GB RAM, NVIDIA NVS 300
Doing each operation 100000 times
style                           total       µsec per call
nop() function:                 0.01578      0.16
nop(), 10x loop unroll:         0.01477      0.15
nop(), 100x loop unroll:        0.01518      0.15
nop() subfunction:              0.01559      0.16
@()[] anonymous function:       0.06400      0.64
nop(obj) method:                0.28482      2.85
nop() private function:         0.01505      0.15
classdef nop(obj):              0.43323      4.33
classdef obj.nop():             0.81087      8.11
classdef private_nop(obj):      0.32272      3.23
classdef class.staticnop():     0.88959      8.90
classdef constant:              1.51890     15.19
classdef property:              0.12992      1.30
classdef property with getter:  1.39912     13.99
+pkg.nop() function:            0.87345      8.73
+pkg.nop() from inside +pkg:    0.80501      8.05
Java obj.nop():                 1.86378     18.64
Java nop(obj):                  0.22645      2.26
Java feval('nop',obj):          0.52544      5.25
Java Klass.static_nop():        0.35357      3.54
Java obj.nop() from Java:       0.00010      0.00
MEX mexnop():                   0.08709      0.87
C nop():                        0.00001      0.00
j() (builtin):                  0.00251      0.03

I think the upshot of this is that:

  • MCOS/classdef methods are faster. Cost is now about on par with old style classes, as long as you use the foo(obj) syntax. So method speed is no longer a reason to stick with old style classes in most cases. (Kudos, MathWorks!)
  • Putting functions in namespaces makes them slow. (Not new in R2011b, just new in my test.)

Update: R2014a

I've reconstructed the benchmarking code and run it on R2014a.

Matlab R2014a on PCWIN64  
Matlab 8.3.0.532 (R2014a) / Java 1.7.0_11 on PCWIN64 Windows 7 6.1 (eilonwy-win7) 
Machine: Core i7-3615QM CPU @ 2.30GHz, 4 GB RAM (VMware Virtual Platform)
nIters = 100000 

Operation                        Time (µsec)  
nop() function:                         0.14 
nop() subfunction:                      0.14 
@()[] anonymous function:               0.69 
nop(obj) method:                        3.28 
nop() private fcn on @class:            0.14 
classdef nop(obj):                      5.30 
classdef obj.nop():                    10.78 
classdef pivate_nop(obj):               4.88 
classdef class.static_nop():           11.81 
classdef constant:                      4.18 
classdef property:                      1.18 
classdef property with getter:         19.26 
+pkg.nop() function:                    4.03 
+pkg.nop() from inside +pkg:            4.16 
feval('nop'):                           2.31 
feval(@nop):                            0.22 
eval('nop'):                           59.46 
Java obj.nop():                        26.07 
Java nop(obj):                          3.72 
Java feval('nop',obj):                  9.25 
Java Klass.staticNop():                10.54 
Java obj.nop() from Java:               0.01 
MEX mexnop():                           0.91 
builtin j():                            0.02 
struct s.foo field access:              0.14 
isempty(persistent):                    0.00 

Update: R2015b: Objects got faster!

Here's R2015b results, kindly provided by @Shaked. This is a big change: OOP is significantly faster, and now the obj.method() syntax is as fast as method(obj), and much faster than legacy OOP objects.

Matlab R2015b on PCWIN64  
Matlab 8.6.0.267246 (R2015b) / Java 1.7.0_60 on PCWIN64 Windows 8 6.2 (nanit-shaked) 
Machine: Core i7-4720HQ CPU @ 2.60GHz, 16 GB RAM (20378)
nIters = 100000 

Operation                        Time (µsec)  
nop() function:                         0.04 
nop() subfunction:                      0.08 
@()[] anonymous function:               1.83 
nop(obj) method:                        3.15 
nop() private fcn on @class:            0.04 
classdef nop(obj):                      0.28 
classdef obj.nop():                     0.31 
classdef pivate_nop(obj):               0.34 
classdef class.static_nop():            0.05 
classdef constant:                      0.25 
classdef property:                      0.25 
classdef property with getter:          0.64 
+pkg.nop() function:                    0.04 
+pkg.nop() from inside +pkg:            0.04 
feval('nop'):                           8.26 
feval(@nop):                            0.63 
eval('nop'):                           21.22 
Java obj.nop():                        14.15 
Java nop(obj):                          2.50 
Java feval('nop',obj):                 10.30 
Java Klass.staticNop():                24.48 
Java obj.nop() from Java:               0.01 
MEX mexnop():                           0.33 
builtin j():                            0.15 
struct s.foo field access:              0.25 
isempty(persistent):                    0.13 

Update: R2018a

Here's R2018a results. It's not the huge jump that we saw when the new execution engine was introduced in R2015b, but it's still an appreciable year over year improvement. Notably, anonymous function handles got way faster.

Matlab R2018a on MACI64  
Matlab 9.4.0.813654 (R2018a) / Java 1.8.0_144 on MACI64 Mac OS X 10.13.5 (eilonwy) 
Machine: Core i7-3615QM CPU @ 2.30GHz, 16 GB RAM 
nIters = 100000 

Operation                        Time (µsec)  
nop() function:                         0.03 
nop() subfunction:                      0.04 
@()[] anonymous function:               0.16 
classdef nop(obj):                      0.16 
classdef obj.nop():                     0.17 
classdef pivate_nop(obj):               0.16 
classdef class.static_nop():            0.03 
classdef constant:                      0.16 
classdef property:                      0.13 
classdef property with getter:          0.39 
+pkg.nop() function:                    0.02 
+pkg.nop() from inside +pkg:            0.02 
feval('nop'):                          15.62 
feval(@nop):                            0.43 
eval('nop'):                           32.08 
Java obj.nop():                        28.77 
Java nop(obj):                          8.02 
Java feval('nop',obj):                 21.85 
Java Klass.staticNop():                45.49 
Java obj.nop() from Java:               0.03 
MEX mexnop():                           3.54 
builtin j():                            0.10 
struct s.foo field access:              0.16 
isempty(persistent):                    0.07 

Update: R2018b and R2019a: No change

No significant changes. I'm not bothering to include the test results.

Update: R2021a: Even faster objects!

Looks like classdef objects have gotten significantly faster again. But structs have gotten slower.

Matlab R2021a on MACI64  
Matlab 9.10.0.1669831 (R2021a) Update 2 / Java 1.8.0_202 on MACI64 Mac OS X 10.14.6 (eilonwy) 
Machine: Core i7-3615QM CPU @ 2.30GHz, 4 cores, 16 GB RAM 
nIters = 100000 

Operation                        Time (μsec)  
nop() function:                         0.03 
nop() subfunction:                      0.04 
@()[] anonymous function:               0.14 
nop(obj) method:                        6.65 
nop() private fcn on @class:            0.02 
classdef nop(obj):                      0.03 
classdef obj.nop():                     0.04 
classdef pivate_nop(obj):               0.03 
classdef class.static_nop():            0.03 
classdef constant:                      0.16 
classdef property:                      0.12 
classdef property with getter:          0.17 
+pkg.nop() function:                    0.02 
+pkg.nop() from inside +pkg:            0.02 
feval('nop'):                          14.45 
feval(@nop):                            0.59 
eval('nop'):                           23.59 
Java obj.nop():                        30.01 
Java nop(obj):                          6.80 
Java feval('nop',obj):                 18.17 
Java Klass.staticNop():                16.77 
Java obj.nop() from Java:               0.02 
MEX mexnop():                           2.51 
builtin j():                            0.21 
struct s.foo field access:              0.29 
isempty(persistent):                    0.26 

Source Code for Benchmarks

I've put the source code for these benchmarks up on GitHub, released under the MIT License. https://github.com/apjanke/matlab-bench

这篇关于MATLAB OOP 速度慢还是我做错了什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆