在多个数据集上运行单个程序
简介
单程序多数据 (spmd) 语言构造允许串行和并行编程的无缝交错。spmd
语句允许您定义一个代码块以在多个工作进程上同时运行。在工作进程的 spmd
语句内分配的变量允许通过 Composite 对象引用直接从客户端访问它们的值。
何时使用 spmd
spmd 的“单程序”特点意味着相同的代码在多个工作进程上运行。您在 MATLAB® 客户端中运行一个程序,其中标记为 spmd
代码块的部分在工作进程上运行。当 spmd 代码块完成后,您的程序将继续在客户端运行。
“多数据”方面意味着即使 spmd
语句在所有工作进程上运行相同的代码,每个工作进程对于该代码可以拥有不同的、唯一的数据。因此,多个数据集可由多个工作进程容纳。
适合 spmd
的典型应用是那些需要在多个数据集上同时执行程序的应用,此时需要在工作进程之间进行通信或同步。一些常见情况如下:
需要很长时间才能执行的程序 -
spmd
允许多个工作进程同时计算解决方案。在大型数据集上运行的程序 -
spmd
让数据分发给多个工作进程。
有关详细信息,请参阅 在 spmd、parfor 和 parfeval 之间选择。
定义 spmd 语句
spmd
语句的一般形式为:
spmd <statements> end
注意
如果并行池没有运行,spmd
将使用您的默认集群配置文件创建一个池(如果您的并行选项已相应设置)。
<statements>
表示的代码块在并行池中的所有工作进程上同时并行执行。如果您希望将执行限制在这些工作进程中的一部分,请准确指定要运行的工作进程数量:
spmd (n) <statements> end
该语句要求 n
个工作进程运行 spmd
代码。n
必须小于或等于打开的并行池中的工作进程数量。如果池足够大,但是 n
工作进程不可用,则该语句将等待,直到有足够的工作进程可用。如果 n
为 0,则 spmd
语句不使用工作进程,并在客户端本地运行,就像当前没有正在运行的池一样。
您可以指定工作进程数量的范围:
spmd (m,n) <statements> end
在这种情况下,spmd
语句至少需要 m
个工作进程,最多需要 n
个工作进程。
如果控制执行 spmd
语句的工作进程数量很重要,请在集群配置文件中或使用 spmd
语句设置精确的数字,而不是使用范围。
例如,针对三个工作进程创建一个随机矩阵:
spmd (3) R = rand(4,4); end
注意
本章中所有后续示例均假设并行池处于打开状态,并且在 spmd
语句序列之间保持打开状态。
与 parfor
循环不同,用于 spmd
语句的每个工作进程对于 spmdIndex
都有一个唯一的值。这使您可以指定仅在某些工作进程上运行的代码,或者自定义执行,通常是为了访问唯一的数据。
例如,根据 spmdIndex
创建不同大小的数组:
spmd (3) if spmdIndex==1 R = rand(9,9); else R = rand(4,4); end end
根据 spmdIndex
在每个工作进程上加载唯一的数据,并在每个工作进程上使用相同的函数从数据中计算结果:
spmd (3) labdata = load(['datafile_' num2str(spmdIndex) '.ascii']) result = MyFunction(labdata) end
执行 spmd
语句的工作进程同时操作并且相互了解。与通信作业一样,您可以直接控制工作进程之间的通信,在它们之间传输数据,并在它们之间使用协同分布数组。
例如,在 spmd
语句中使用协同分布数组:
spmd (3) RR = rand(30, codistributor()); end
每个工作进程都有一个 30×10 的协同分布数组 RR
段。有关协同分布数组的更多信息,请参阅 使用协同分布数组。
显示输出
在并行池上运行 spmd
语句时,来自工作进程的所有命令行输出都会显示在客户端命令窗口中。由于工作进程是没有显示的 MATLAB 会话,所以来自池的任何图形输出(例如,图形窗口)根本不会显示。
MATLAB 路径
所有执行 spmd
语句的工作进程必须具有与客户端相同的 MATLAB 搜索路径,以便他们可以执行在其公共代码块中调用的任何函数。因此,无论何时在客户端上使用 cd
、addpath
或 rmpath
,如果可能的话,它也会在所有工作进程上执行。有关更多信息,请参阅 parpool
参考页。当工作进程在与客户端不同的平台上运行时,使用函数 pctRunOnAll
在所有工作进程上正确设置 MATLAB 路径。
错误处理
当工作进程在执行 spmd
语句期间发生错误时,该错误会报告给客户端。客户端尝试中断所有工作进程的执行,并向用户抛出错误。
工作进程上产生的错误和警告用工作进程 ID(spmdIndex
)注释,并按照 MATLAB 客户端接收的顺序显示在客户端的命令窗口中。
如果在 spmd
的主体内使用,则 lastwarn
的行为在该代码块的末尾是未指定的。
spmd 限制
嵌套函数
在函数内部,spmd
语句的主体不能引用嵌套函数。但是,它可以通过将变量定义为嵌套函数的函数句柄来调用嵌套函数。
因为 spmd
函数体在工作进程上执行,所以由 spmd
语句内调用的嵌套函数更新的变量不会在外部函数的工作区中更新。
嵌套 spmd
语句
spmd
语句的主体不能直接包含另一个 spmd
。但是,它可以调用包含另一个 spmd
语句的函数。内部的 spmd
语句不在另一个并行池中并行运行,而是在运行其包含函数的工作进程上的单个线程中串行运行。
嵌套 parfor
循环
spmd
语句不能包含 parfor
循环,并且 parfor
循环的主体不能包含 spmd
语句。原因是工作进程无法启动或访问进一步的并行池。
break
、continue
和 return
语句
spmd
语句的主体不能包含 break
、continue
或 return
语句。考虑使用 parfeval
或 parfevalOnAll
而不是 spmd
,因为您可以在它们上使用 cancel
。
全局变量和持久变量
spmd
语句的主体不能包含 global
或 persistent
变量声明。原因是这些变量在工作进程之间不同步。您可以在函数中使用 global
或 persistent
变量,但它们的值只有创建它们的工作进程才可见。与使用 global
变量相比,使用函数参量来共享值是一种更好的做法。
匿名函数
spmd
语句的主体不能定义匿名函数。但是,它可以通过函数句柄引用匿名函数。
inputname
函数
spmd
内部不支持使用 inputname
返回与参量编号对应的工作区变量名称。原因是 spmd
工作进程无法访问 MATLAB 桌面的工作区。为了解决此问题,请在 spmd
之前调用 inputname
,如下例所示。
a = 'a'; myFunction(a) function X = myFunction(a) name = inputname(1); spmd X.(name) = spmdIndex; end X = [X{:}]; end
load
函数
spmd
语句内不支持未分配给输出结构的 load
语法。在 spmd
内部,始终将 load
的输出分配给一个结构。
nargin
或 nargout
函数
spmd
语句中不支持以下用法:
使用不带函数参量的
nargin
或nargout
使用
narginchk
或nargoutchk
来验证当前正在执行的函数调用中的输入或输出参量的数量
原因是工作进程无法访问 MATLAB 桌面的工作区。为了解决此问题,请在 spmd
之前调用这些函数。
myFunction('a','b') function myFunction(a,b) nin = nargin; spmd X = spmdIndex*nin; end end
P 代码脚本
您可以从 spmd
语句中调用 P 代码脚本文件,但 P 代码脚本不能包含 spmd
语句。要解决此问题,请使用 P 代码函数而不是 P 代码脚本。
ans
变量
spmd
语句内不支持对在 spmd
语句外定义的 ans
变量的引用。在 spmd
语句的主体内,必须先分配 ans
变量,然后才能使用它。
另请参阅
spmd
| parfor
| parfeval
| parfevalOnAll
| distributed
| Composite