MATLAB函数按引用传递

4

我有一个属性类(假设类文件名为inputvar)。

我将它作为两个不同函数的输入参数,这两个函数的计算方式完全相同,但代码略有不同,稍后我会解释。

对于第一个函数(假设名称为myfun1),我像这样编写输入参数:

f = myfun1 (inputvar)

因此,每次在函数内部使用类中的变量时,都必须调用inputvar.var1inputvar.var2等。

对于第二个函数(myfun2),我在输入参数中写入类中的每个变量,代码如下所示:

f = myfun2 (inputvar.var1, inputvar.var2, ... etc )

在函数内部,我只需要使用var1var2等,而无需包含类的名称。

运行这两个函数后,我发现myfun2myfun1快很多,大约快60% (我使用了tic-toc)。

有人能够解释一下具体原因吗?


尝试使用句柄类,参见http://www.mathworks.com/help/matlab/ref/handle.html。 - jsp
http://stackoverflow.com/questions/16529681/advice-with-pointers-in-matlab/16530323#16530323 - Oleg
2个回答

3
我发现在Matlab中访问属性非常慢。我还没有找到解决方法,但一些基本的想法可以在这里找到:http://blogs.mathworks.com/loren/2012/03/26/considering-performance-in-object-oriented-matlab-code/
但是,这篇文章只谈到了避免可怕、糟糕的性能问题。即使是最简单的属性,性能也不尽如人意。
以Mathworks文章中的示例类为例。我进行了小型测试脚本:
clear all
clc
n = 1e5;
%% OOP way - abysimal
result = zeros(1, n);
tic
for i = 1:n
    cyl = SimpleCylinder();
    cyl.R = i;
    cyl.Height = 10;
    result(i) = cyl.volume();
end
toc
%% OOP Vectorized - fair
clear result
tic
cyl = SimpleCylinder();
cyl.R = 1:n;
cyl.Height = 10;
result = cyl.volume();
toc
%% for loop without objects - good
result = zeros(1, n);
tic
for i = 1:n
    result(i) = pi .* i.^2 .* 10;
end
toc
%% Vectorized without objects - excellent
clear result
tic
R = 1:n;
result = pi .* R.^2 .* 10;
toc

通过这些结果:

Elapsed time is 6.141445 seconds.
Elapsed time is 0.006245 seconds.
Elapsed time is 0.002116 seconds.
Elapsed time is 0.000478 seconds.

正如您所看到的,每次属性访问都会减慢速度。尝试进行向量化(一如既往),但即使是简单的for循环在小n的情况下也比向量化的OOP解决方案更快。(在我的PC上,它们在1e7时相当)。
重要信息:Matlab中的OOP很慢!您为每个属性访问付出代价。
对于您的问题:当您调用
myfun2 (inputvar.var1, inputvar.var2, ... etc )

这些值是被复制的。在函数内部,您不再处理类。变量的访问速度很快。但是,如果您传递整个类,则每次访问属性都会变慢。您可以通过将所有属性缓存在局部变量中并使用这些变量来规避这个问题。


如果您修改类以继承自handle,则所有内容都会变得更快,但差异微乎其微。


正如我所说,导致速度变慢的是属性访问。每次使用点号(比如“inputvar.var1”)访问时都会拖慢速度。 - DasKrümelmonster

3

使用引用时:

MATLAB使用一种通常被称为“写时复制”的系统,以避免在函数工作区内复制输入参数,直到您修改输入参数。如果不修改输入参数,则MATLAB将避免进行复制。例如,在此代码中:

function y = functionOfLargeMatrix(x) y = x(1); MATLAB不会在functionOfLargeMatrix的工作区内复制输入,因为x在该函数中未被更改。另一方面,如果您调用了这个函数:

function y = functionOfLargeMatrix2(x) x(2) = 2; y = x(1); 那么x在functionOfLargeMatrix2的工作区内被修改,因此必须进行复制。

根据上述声明,当您直接传递一个类对象并更改该对象的任何成员时,将应用整个类的复制操作。

另一方面,通过将类成员作为单独的参数传递,仅对函数中修改的相关成员应用复制操作,从而实现更快的执行。

但即使我没有改变对象的任何成员,情况仍然是一样的。有什么想法为什么? - saiful
@Tom_Crusoe 如果您再次传递输入,MATLAB会创建一个副本吗?即function [y,x] = functionOfLargeMatrix(x)x(2)= 2; y = x(1);是否创建x的副本? - rodms

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