appdata 是否在并行池中的工作人员之间共享?

Is appdata shared between workers in a parallel pool?

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

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

我的问题是 - 我如何判断 global and/or persistent and/or [=15 中的数据=] 是在工人之间共享还是每个人都是唯一的?

几个可能相关的事情:

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

我知道每个worker对应一个新的进程,有自己的内存space(大概是global/persistent/appdata workspace).基于此和 this official comment,我认为这种共享很可能不会发生......但我们如何确定它?

相关material:

  1. This Q&A.
  2. This documentation page.

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

第 1 步:手动生成 "Workers"

首先,创建这 3 个函数:

%% 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 实例(代表一个并行池的两个不同的 worker),然后 运行 q52623266_W1 在其中一个上,等待它完成,然后 运行 q52623266_W2 另一边。如果数据 共享,则 2nd 实例将打印一些内容。这导致(在 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 类似,用于此测试。

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

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

为了演示,创建了一个带有持久变量的简单函数 (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 - this means worker that completed 15 continued with 14 next"

来完成其工作

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

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