类的示例代码:
classdef testcls
methods
function sayhello(~)
disp('Hello! ')
end
end
end
现在如果我调用
parfor
中的方法,如下所示
A = testcls;
parfor ii = 1:4
A.sayhello()
end
Mlint 告诉我在循环中使用
A
的性能问题:
整个数组或结构体“obj”是一个广播变量。这可能会导致不必要的通信开销。
我可以使用匿名函数来抑制此消息:
A = testcls;
f = @A.sayhello;
parfor ii = 1:4
f()
end
但我的问题是,这样做对提高速度有帮助吗?有没有更好的方法来调用
parfor
中的方法?
那么,如果我想设置函数的输入/输出参数,情况会变得更复杂吗?
classdef testcls
methods
function [out1,out2] = sayhello(~,n)
out1 = (['Hello! ', num2str(n)]);
out2 = n;
end
end
end
A = testcls;
f = @A.sayhello;
[a,b] = deal(cell(4,1));
parfor ii = 1:4
[a{ii},b{ii}] = feval(f,ii);
end
编辑:
我观察到与内存复制操作相关的大量资源消耗。基本上,作业调度程序将为每个工作人员创建一个相同的对象,包括所有修改的属性。
f = @A.sayhello;
的用法并不能避免Matlab将整个对象memcpy到每个单独的worker中,即使该方法本身不调用或存储任何类属性。
我认为这是确保透明度的方法。然而,当数据量巨大时,这将成为一个巨大的难题。
是否有一种方法,可以将
sayhello
打包在不会调用整个对象的内存复制的对象中,而不是将所需的函数隔离到独立的基于文件的函数中?
编辑:感谢@gnovice 的建议性答案。我制作了一个测试用例,以便比较
parfor
与静态方法、parfor
与非静态方法以及使用 arrayfun
的串行执行。
测试用例1:
parfor
采用非静态方法(对照)
从内存使用记录中可以看出,单个对象
testcls
的创建使用了约700MB RAM,由标签1
表示,后面是标记为clear
的2
命令,以及 parfor
循环在标签 3
上方运行。 parfor
的峰值使用量大约是单个对象的 4 倍,而池中有 4 个工作线程。
测试用例 2:
parfor
使用静态方法
测试程序以相同的方式完成并标记。从这个证据来看,结论是,仅使方法静态并不能阻止 parpool 为所有工作线程生成相同的对象。
测试案例 3:使用
arrayfun
进行系列评估
由于
arrayfun
执行非顺序串行批量评估,因此 arrayfun
没有理由使用比单个线程所需的更多内存。因此就有了证据。
示例代码:
classdef testcls
properties
D
end
methods (Static = false)
function [out1,out2] = sayhello(~,n)
out1 = (['Hello! ', num2str(n)]);
out2 = n;
end
end
methods
function obj = testcls(~)
obj.D = rand(1e8,1);
end
end
end
要运行测试,请使用以下脚本:
clear;clc;close all
A = testcls;
f = @A.sayhello;
parfor ii = 1:4
feval(f,ii)
end
您可以将
parfor
替换为 arrayfun
以进行序列验证。
对于不必引用类的任何属性的方法,最好将它们设为静态方法。来自文档:
静态方法与类关联,但与该类的特定实例无关。与对类的特定对象进行操作的普通方法不同,这些方法不需要类的对象作为输入参数。您可以调用静态方法而不创建类的对象
由于无需创建该类的对象即可调用它们,这应该可以帮助您避免每个工作人员之间不必要的整个对象的重复。
方法示例:
classdef testcls
...
methods(Static)
function sayhello
disp('Hello!');
end
end
...
end
并从每个工人那里调用它:
testcls.sayhello();
同样的问题,除了我的方法函数需要使用类属性,并且“整个数组或结构‘obj’是一个广播变量。”问题没有解决.:(