Labfans是一个针对大学生、工程师和科研工作者的技术社区。 论坛首页 | 联系我们(Contact Us)
MATLAB爱好者论坛-LabFans.com
返回   MATLAB爱好者论坛-LabFans.com > 其它 > 资料存档
资料存档 资料存档
回复
 
主题工具 显示模式
旧 2019-12-10, 16:49   #1
poster
高级会员
 
注册日期: 2019-11-21
帖子: 3,006
声望力: 66
poster 正向着好的方向发展
帖子 是MATLAB OOP运行缓慢还是我做错了什么?

我正在尝试使用MATLAB OOP ,从一开始就模仿了C ++的Logger类,并将所有的字符串帮助器函数都放在String类中,认为能够执行a + b , a == b , a.find( b )代替strcat( ab ) , strcmp( a, b ) ,检索strfind( a, b )第一个元素,等等。

问题:减速

我使用了上面的东西,立即注意到速度急剧下降。我做错了吗(由于我有限的MATLAB经验,这肯定是可能的),还是MATLAB的OOP只会带来很多开销?

我的测试用例

这是我对字符串所做的简单测试,基本上只是添加一个字符串,然后再次删除添加的部分:
注意:实际不要在实际代码中编写像这样的String类! Matlab现在具有本机string数组类型,您应该使用它。

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 = [ ab ]; 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' ); 结果

1000次迭代的总时间(以秒为单位):
btest 0.550(使用String.SetLength 0.138,String.plus 0.065,String.Length 0.057)

验证0.015

记录器系统的结果也是如此:内部使用String类时frpintf( 1, 'test\n' )对frpintf( 1, 'test\n' )进行1000次调用需要0.1秒,对我的系统进行1000次调用需要7(!)秒(确定,它还有很多其他功能)逻辑,但要与C ++进行比较:在输出端使用std::string( "blah" )和std::cout系统开销与普通std::cout > call_nops计算机:PCWIN版本:2009b调用每个函数/方法100000次nop()函数:0.02261秒每次调用0.23 uscnop1-5()函数:0.02182秒每次调用0.22 uscnop()子函数:0.02244秒每次调用0.22 usc@()[]匿名函数:每次通话0.08461秒0.85微秒nop(obj)方法:每次调用0.24664秒2.47 uscnop1-5(obj)方法:每次调用0.23469秒2.35 uscnop()私有函数:0.02197秒每次调用0.22 uscclassdef nop(obj):每个调用0.90547秒9.05 usecclassdef obj.nop():1.75522秒17.55 usc每个调用classdef private_nop(obj):0.84738秒8.47 usc每个调用classdef nop(obj)(m文件):每次调用0.90560秒9.06 uscclassdef class.staticnop():每个调用1.16361秒11.64微秒Java nop():2.43035秒每个调用24.30 uscJava static_nop():0.87682秒8.77每次调用usecJava中的Java nop():0.00014秒每次调用0.00 uscMEX mexnop():每个通话0.11409秒1.14 uscC nop():0.00001秒每次调用0.00 usc R2008a到R2009b的结果相似。这是在运行32位MATLAB的Windows XP x64上。

“ Java nop()”是在M代码循环内调用的虚无Java方法,并且每次调用都包括从MATLAB到Java的调度开销。 “ Java的Java nop()来自Java”是在Java for()循环中调用的同一件事,不会引起边界损失。用一点时间来了解Java和C的计时;一个聪明的编译器可以完全优化调用。

包作用域机制是新的,与classdef类几乎同时引入。它的行为可能是相关的。

一些初步的结论:
  • 方法比函数慢。
  • 新样式(classdef)方法比旧样式方法慢。
  • 即使对于classdef对象使用相同的方法,新的obj.nop()语法也比nop(obj)语法慢。与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退出了,性能图片已足够更改以进行更新。

拱门:PCWIN版本:2011b 机器:R2011b,Windows XP,8x Core i7-2600 @ 3.40GHz,3 GB RAM,NVIDIA NVS 300每次操作100000次每次呼叫样式总计secnop()函数:0.01578 0.16nop(),10次循环展开: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.90classdef常数:1.51890 15.19classdef属性:0.12992 1.30使用getter的classdef属性:1.39912 13.99+ pkg.nop()函数:0.87345 8.73内部+ pkg + pkg.nop():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.54Java中的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)语法,成本就与旧样式类foo(obj) 。因此,在大多数情况下,方法速度不再是坚持使用旧样式类的原因。 (荣誉,MathWorks!)
  • 将函数放在名称空间中会使它们变慢。 (在R2011b中不是新增功能,在我的测试中只是新增功能。)
更新:R2014a

我已经重构了基准测试代码,并在R2014a上运行了它。

在PCWIN64上的Matlab R2014a 在PCWIN64 Windows 7 6.1(eilonwy-win7)上的Matlab 8.3.0.532(R2014a)/ Java 1.7.0_11 机器:Core i7-3615QM CPU @ 2.30GHz,4 GB RAM(VMware Virtual Platform)nIters = 100000 动作时间(μsec) nop()函数:0.14 nop()子函数:0.14 @()[]匿名函数:0.69 nop(obj)方法:3.28 @class上的nop()private fcn: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常数:4.18 classdef属性:1.18 具有getter的classdef属性:19.26 + pkg.nop()函数:4.03 内部+ pkg + pkg.nop():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中的Java obj.nop():0.01 MEX mexnop():0.91 内置j():0.02 struct s.foo字段访问:0.14 空(持续):0.00 更新:R2015b:对象变得更快!

这是R2015b的结果,由@Shaked提供。这是一个很大的变化:OOP显着提高了速度,现在obj.method()语法与method(obj)一样快,并且比传统的OOP对象要快得多。

PCWIN64上的Matlab R2015b 在PCWIN64 Windows 8 6.2上的Matlab 8.6.0.267246(R2015b)/ Java 1.7.0_60(nanit-shaked) 机器:Core i7-4720HQ CPU @ 2.60GHz,16 GB RAM(20378)nIters = 100000 操作时间(μsec) nop()函数:0.04 nop()子函数:0.08 @()[]匿名函数:1.83 nop(obj)方法:3.15 @class上的nop()private fcn: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常数:0.25 classdef属性:0.25 具有getter的classdef属性:0.64 + pkg.nop()函数:0.04 内部+ pkg + pkg.nop():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中的Java obj.nop():0.01 MEX mexnop():0.33 内置j():0.15 struct s.foo字段访问:0.25 isempty(持续):0.13 更新:R2018a

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

MACI64上的Matlab R2018a Matlab 9.4.0.813654(R2018a)/ MACI64 Mac OS X 10.13.5上的Java 1.8.0_144(eilonwy) 机器:Core i7-3615QM CPU @ 2.30GHz,16 GB RAM nIters = 100000 动作时间(μsec) nop()函数:0.03 nop()子函数:0.04 @()[]匿名函数: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常数:0.16 classdef属性:0.13 具有getter的classdef属性:0.39 + pkg.nop()函数:0.02 内部+ pkg + pkg.nop():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的Java obj.nop():0.03 MEX mexnop():3.54 内置j():0.10 struct s.foo字段访问:0.16 isempty(永久):0.07 更新:R2018b和R2019a:不变

没有重大变化。我不愿意包含测试结果。

基准的源代码

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



更多&回答...
poster 当前离线   回复时引用此帖
回复

主题工具
显示模式

发帖规则
不可以发表新主题
不可以发表回复
不可以上传附件
不可以编辑自己的帖子

启用 BB 代码
论坛禁用 表情符号
论坛启用 [IMG] 代码
论坛启用 HTML 代码



所有时间均为北京时间。现在的时间是 20:49


Powered by vBulletin
版权所有 ©2000 - 2025,Jelsoft Enterprises Ltd.