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

问题描述 投票:0回答:2

类的示例代码:

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
采用非静态方法(对照)

parfor non-static

从内存使用记录中可以看出,单个对象

testcls
的创建使用了约700MB RAM,由标签
1
表示,后面是标记为
clear
2
命令,以及
 parfor
循环在标签
3
上方运行。
parfor
的峰值使用量大约是单个对象的 4 倍,而池中有 4 个工作线程。

测试用例 2:

parfor
使用静态方法

parfor static

测试程序以相同的方式完成并标记。从这个证据来看,结论是,仅使方法静态并不能阻止 parpool 为所有工作线程生成相同的对象。

测试案例 3:使用

arrayfun

进行系列评估

serial

由于

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

matlab parfor
2个回答
1
投票

对于不必引用类的任何属性的方法,最好将它们设为静态方法。来自文档:

静态方法与类关联,但与该类的特定实例无关。与对类的特定对象进行操作的普通方法不同,这些方法不需要类的对象作为输入参数。您可以调用静态方法而不创建类的对象

由于无需创建该类的对象即可调用它们,这应该可以帮助您避免每个工作人员之间不必要的整个对象的重复。

方法示例:

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

并从每个工人那里调用它:

testcls.sayhello();

0
投票

同样的问题,除了我的方法函数需要使用类属性,并且“整个数组或结构‘obj’是一个广播变量。”问题没有解决.:(

© www.soinside.com 2019 - 2024. All rights reserved.