3

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

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

我的问题是- 我如何判断数据global和/或persistent和/或appdata在工人之间共享还是每个人独有?

几个可能相关的事情:

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

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

相关资料:

  1. 本问答
  2. 此文档页面
4

2 回答 2

3

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

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

首先,创建这 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 实例(代表并行池的两个不同工作器),然后q52623266_W1在其中一个上运行,等待它完成,然后q52623266_W2在另一个上运行。如果数据共享的,第二个实例将打印一些东西。这导致(在 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

于 2018-10-03T09:31:29.740 回答
3

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

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

为了演示,创建了一个带有持久变量的简单函数(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,它就可以正常工作并且看起来很优雅……但之后就坏了。使用对象。

于 2018-10-03T11:16:03.200 回答