【问题标题】:Is appdata shared between workers in a parallel pool?appdata 是否在并行池中的工作人员之间共享?
【发布时间】:2019-03-08 11:04:24
【问题描述】:

我正在处理一个调用多个子函数(在同一个文件中)的复杂函数。为了传递数据,偶尔使用setappdata/getappdata 机制。此外,一些子函数包含persistent 变量(为了以后节省计算而初始化一次)。

我一直在考虑是否可以在并行池中的多个工作人员上执行此功能,但开始担心可能会有一些意外的数据共享(否则每个工作人员都是唯一的)。

我的问题是 - 我如何判断 global 和/或 persistent 和/或 appdata 中的数据是在工作人员之间共享还是对每个工作人员唯一?

一些可能相关的事情:

  1. 就我而言,任务是完全并行的,它们的结果不应以任何方式相互影响(并行化只是为了节省时间)。
  2. 没有创建任何临时文件或文件夹,因此不会有一名工作人员错误地读取另一名工作人员留下的文件的风险。
  3. 所有persistent 和appdata 存储的变量都是在parfor 子函数中创建/分配的。

我知道每个worker对应一个拥有自己内存空间的新进程(大概是global/persistent/appdata工作区)。基于此和this official comment,我会说这种共享很可能不会发生……但是我们如何确定呢?

相关资料:

  1. This Q&A
  2. This documentation page

【问题讨论】:

  • 我没有太多要添加到我的“官方评论”(!) - 但无论如何,所有globalpersistentappdata 的东西都不会在 Parallel Computing Toolbox 工作人员之间共享过程。 (通常人们希望它是。)
  • @Edric 感谢您的评论。因为你在 MA 上有一个 [STAFF] 标签,所以这几乎是官方的。 :)

标签: matlab parallel-processing global-variables persistent-storage app-data


【解决方案1】:

这很容易测试,我们将分两个阶段进行。

第 1 步:手动生成“工人”

首先,创建这三个函数:

%% Worker 1:
function q52623266_W1
global a; a = 5;
setappdata(0, 'a', a);
someFuncInSameFolder();
end

%% Worker 2:
function q52623266_W2
global a; disp(a);
disp(getappdata(0,'a'));
someFuncInSameFolder();
end

function someFuncInSameFolder()
  persistent b; 
  if isempty(b)
    b = 10;
    disp('b is now set!');
  else
    disp(b);
  end
end

接下来,我们启动 2 个 MATLAB 实例(代表并行池的两个不同工作器),然后在其中一个上运行 q52623266_W1,等待它完成,然后在另一个上运行 q52623266_W2。如果数据共享的,第二个nd实例会打印一些东西。这导致(在 R2018b 上):

>> q52623266_W1
b is now set!

>> q52623266_W2
b is now set!

这意味着数据不共享。到目前为止一切都很好,但有人可能想知道这是否代表了一个实际的并行池。所以我们可以稍微调整一下我们的功能,然后继续下一步。

第 2 步:自动生成工人

function q52623266_Host

spmd(2)
  if labindex == 1
    setupData();
  end
  labBarrier; % make sure that the setup stage was executed.
  if labindex == 2
    readData();
  end  
end

end

function setupData
  global a; a = 5;
  setappdata(0, 'a', a);
  someFunc();
end

function readData
  global a; disp(a);
  disp(getappdata(0,'a'));
  someFunc();
end

function someFunc()
  persistent b; 
  if isempty(b)
    b = 10;
    disp('b is now set!');
  else
    disp(b);
  end
end

运行上面我们得到:

>> q52623266_Host
Starting parallel pool (parpool) using the 'local' profile ...
connected to 2 workers.
Lab 1: 
  b is now set!
Lab 2: 
  b is now set!

这又意味着数据未共享。请注意,在第二步中,我们使用了spmd,在本次测试中,它的功能应该类似于parfor

【讨论】:

    【解决方案2】:

    还有一个不共享数据让我很不爽。

    持久变量甚至不会从当前工作区复制到工作人员。

    为了演示,创建了一个带有持久变量的简单函数 (MATLAB 2017a):

    function [ output_args ] = testPersist( input_args )
    %TESTPERSIST Simple persistent variable test.
    
    persistent var
    
    if (isempty(var))
        var = 0;
    end
    if (nargin == 1)
        var = input_args;
    end
    
    output_args = var;
    
    end
    

    然后执行一个简短的脚本:

    testPersist(123); % Set persistent variable to 123.
    tpData = zeros(100,1);
    parfor i = 1 : 100
        tpData(i) = testPersist;
        testPersist(i);
    end
    any(tpData == 0) % This implies the worker started from 0 instead of 123 as specified in the first row.
    

    输出为 1 - 工作人员忽略了父工作区中的 123 并重新开始。

    检查tpData 中的值还可以通过注释“tpData(14) = 15 - 这意味着完成 15 的工人继续下一个 14”来显示每个工人如何完成工作

    因此,创建一个 worker = 创建一个全新的 MATLAB 实例,与您面前打开的 MATLAB 实例完全无关。分别为每个工人。

    我从中获得的教训 = 不要使用简单的持久变量作为模拟配置文件。只要不使用 parfor,它就可以正常工作并且看起来很优雅......但之后可怕地坏了。使用对象。

    【讨论】:

      猜你喜欢
      • 2019-04-22
      • 1970-01-01
      • 2012-02-03
      • 1970-01-01
      • 2017-08-23
      • 2019-07-02
      • 1970-01-01
      • 1970-01-01
      • 2017-03-02
      相关资源
      最近更新 更多