在 parfor 循环中引用 class 方法:显着的内存使用

Referring to class method in parfor loop: significant memory usage

class 的示例代码:

classdef testcls
    methods
        function sayhello(~)
            disp('Hello! ')
        end
    end 
end

现在,如果我调用 parfor 中的方法,如下所示

A = testcls;
parfor ii = 1:4
    A.sayhello()
end

Mlint 告诉我在循环中使用 A 的性能问题:

The entire array or structure 'obj' is a broadcast variable. This might result in unnecessary communication overhead.

而且我可以使用匿名函数来抑制此消息:

A = testcls;
f = @A.sayhello;
parfor ii = 1:4
    f()
end

但我的问题是,这样做是否有助于提高速度?在parfor中调用方法有没有更好的方法?

那么,如果我要设置函数的input/output个参数,情况会不会变得更复杂?

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,即使方法本身不调用或存储任何 class 属性。

我认为这是确保透明度的方法。但是当数据量很大的时候,这就会成为一个很头疼的问题。

有没有一种方法可以将 sayhello 打包到对象中而不调用整个对象的内存复制,而不是将所需的函数隔离到独立的基于文件的函数中?


编辑:感谢@gnovice 的建议性回答。我制作了一个测试用例,以便比较 parfor 与静态方法、parfor 与非静态方法以及使用 arrayfun 的串行执行。

测试用例 1:parfor 使用非静态方法(控制)

从内存使用记录中可以看出,创建单个对象testcls使用~700MB RAM,由标签1表示,其后是clear命令标记为 2parfor 循环 运行 位于标签 3 之上。 parfor 的峰值使用量大约是单个对象的 4 倍,而池有 4 个 worker。

测试用例 2:parfor 使用静态方法

测试程序以相同的方式完成并标记。根据这一证据,结论是仅使方法静态化并不能阻止 parpool 为所有 worker 生成相同的对象。

测试用例 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 以进行序列验证。

对于不必引用 class 中的任何 属性 的方法,最好将它们设为 static methods。来自文档:

Static methods are associated with a class, but not with specific instances of that class. These methods do not require an object of the class as an input argument, unlike ordinary methods which operate on specific objects of the class. You can call static methods without creating an object of the class

由于无需创建对象即可调用它们 class,这应该可以帮助您避免整个对象在每个 worker 中不必要的重复。

示例方法:

classdef testcls
  ...
  methods(Static)
    function sayhello
      disp('Hello!');
    end
  end
  ...
end

并从每个工人调用它:

testcls.sayhello();