在多个数据集上运行单个程序
简介
单程序多数据 (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 变量
ans 语句内不支持对在 spmd 语句外定义的 spmd 变量的引用。在 spmd 语句的主体内,必须先分配 ans 变量,然后才能使用它。
复合变量与分布式变量在数据容器中的应用
复合型和分布式数组必须作为自己的顶级变量出现在 spmd 语句中,不能隐藏在其他数据容器(如结构、元胞数组或对象)中。
在此示例中,将复合对象 C 存储在元胞数组 Y 中,然后将其用作 spmd 语句中的输入变量。因此,MATLAB 在运行时发出警告:
spmd; C = 5; end Y = {C}; spmd disp(Y) end
同样,您不能在 spmd 语句中使用存储在对象(如 dictionary)中的复合或分布数组。在此示例中,dd 是一个无效的分布式数组,CC 是一个无效的复合数组:
spmd; C = 5; d = ones(7,"codistributed"); end X = dictionary(["dist","comp"],{d,C}); spmd dd = X{"dist"} CC = X{"comp"} end
作为解决方法,从数据结构中提取复合或分布数组,并在 spmd 语句之前将其分配给一个单独的变量:
spmd; C = 5; d = ones(7,"codistributed"); end X = dictionary(["dist","comp"],{d,C}); dd = X{"dist"}; CC = X{"comp"}; spmd disp(dd) disp(CC) end
另请参阅
spmd | parfor | parfeval | parfevalOnAll | distributed | Composite