1

Matlab 中用类封装函数

 3 years ago
source link: https://zhiqiang.org/coding/class-wrapper-functions-in-matlab.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Matlab 中用类封装函数

作者: 张志强

, 发表于 2010-09-24

, 共 1875 字 , 共阅读 508 次

上次大规模使用 Matlab 还是本科的时候,当时还是 5.3 版,现在重新尝试它,已经是 7.8 ( R2009a ),而且 R2010b 版都已经发售。而这些版本引入的一个新玩意儿便是面向对象化编程( object-oriented programming , OOP )。

使用类( class )有很多好处,其中一个重要的好处便是解决变量名冲突和让函数、对象的结构清晰。class 的 static function 可以在不定义类的实例直接调用类的成员函数,比如定义

classdef tools < handle
    methods (Static = true)
        function a = test(b, c)
            a = b + c;
        end
    end
end

然后可以直接通过

a = tools.test(b, c);

调用 test 函数。这样做的好处是解决 test 的变量名冲突问题,而且可以将类似的函数封装到一块,使得函数结构显示层次化。

但这样做是有代价的,其中一个便是效率问题,假设还有一个完全一样的用普通 m 文件定义的 test 函数,下面两段代码测试了这两者各运行一百万次所需的时间:

tic
for i = 1:1000000, test(i, i); end
toc

tic
for i = 1:1000000, tools.test(i, i); end
toc

那么普通函数的百万次调用的时间开销约 0.25 秒,而封装后的函数的百万次调用的时间开销高达 14.5 秒,相差约 70 倍。而且如果通过 class 的实例来调用,所需要的时间更长,下面这段代码显示百万次调用需要 22.5 秒。

t = tools;
tic
for i = 1:1000000, t.test(i, i); end
toc

所以到底该不该封装,还需取决于实际情况,如果函数本身特别简单,并且会被循环调用,最好还是通过 m 文件函数的形式。之前 MIT 大牛给出了更多地建议

  1. 虽然 for-loop 的速度有了很大改善, vectorization (向量化)仍旧是改善效率的重要途径,尤其是在能把运算改写成矩阵乘法的情况下,改善尤为显著。
  2. 在不少情况下, for-loop 本身已经不构成太大问题,尤其是当循环体本身需要较多的计算的时候。这个时候,改善概率的关键在于改善循环体本身而不是去掉 for-loop。
  3. MATLAB 的函数调用过程(非 built-in function )有显著开销,因此,在效率要求较高的代码中,应该尽可能采用扁平的调用结构,也就是在保持代码清晰和可维护的情况下,尽量直接写表达式和利用 built-in function ,避免不必要的自定义函数调用过程。在次数很多的循环体内(包括在 cellfun, arrayfun 等实际上蕴含循环的函数)形成长调用链,会带来很大的开销。
  4. 在调用函数时,首选 built-in function ,然后是普通的 m-file 函数,然后才是 function handle 或者 anonymous function。在使用 function handle 或者 anonymous function 作为参数传递时,如果该函数被调用多次,最好先用一个变量接住,再传入该变量。这样,可以有效避免重复的解析过程。
  5. 在可能的情况下,使用 numeric array 或者 struct array ,它们的效率大幅度高于 cell array (几十倍甚至更多)。对于 struct ,尽可能使用普通的域(字段, field )访问方式,在非效率关键,执行次数较少,而灵活性要求较高的代码中,可以考虑使用动态名称的域访问。
  6. 虽然 object-oriented 从软件工程的角度更为优胜,而且 object 的使用很多时候很方便,但是 MATLAB 目前对于 OO 的实现效率很低,在效率关键的代码中应该慎用 objects。
  7. 如果需要设计类,应该尽可能采用普通的 property ,而避免灵活但是效率很低的 dependent property。如非确实必要,避免重载 subsref 和 subsasgn 函数,因为这会全面接管对于 object 的接口调用,往往会带来非常巨大的开销(成千上万倍的减慢),甚至使得本来几乎不是问题的代码成为性能瓶颈。

Q. E. D.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK