之间做出选择spmd
,parfor
,parfeval
并行代码通信
要并行运行计算,可以使用parfor
,parfeval
,parfevalOnAll
,或spmd
.每个构造都依赖于不同的并行编程概念。如果您要求工作人员在整个计算过程中进行通信,请使用parfeval
,parfevalOnAll
,或spmd
.
使用
parfeval
或parfevalOnAll
如果您的代码可以拆分为一组任务,其中每个任务可以依赖于其他任务的输出。使用
spmd
如果在计算过程中需要工作人员之间的通信。
计算与parfeval
最好用图表来表示,类似于带块的看板。一般来说,结果是在计算完成后从worker那里收集的。类的执行可以收集结果parfeval
使用操作afterEach
或毕竟
.您通常在进一步的计算中使用这些结果。
计算与spmd
最好用流程图来表示,类似于瀑布工作流。执行一个池工作人员spmd
语句被称为实验室。结果可以在计算过程中从实验室收集。有时,实验室在完成计算之前必须与其他实验室进行交流。
如果你不确定,问自己以下问题:在我的通信并行代码中,每个计算是否可以在没有任何工作者之间的通信的情况下完成?如果是,请使用parfeval
.否则,使用spmd
.
同步和异步工作
当你在parfor
,parfeval
,spmd
,考虑您的计算是否需要与客户端同步。
parfor
而且spmd
需要同步,因此阻止你在MATLAB上运行任何新的计算®客户端。parfeval
不需要同步,因此客户端可以自由地进行其他工作。
比较多线程和ProcessPool
在本例中,您将比较函数在客户机和客户机上运行的速度ProcessPool
.一些MATLAB函数使用多线程。使用这些函数的任务在多线程上比在单个线程上执行得更好。因此,如果在具有多核的机器上使用这些函数,本地集群的性能可能比客户机上的多线程还要差。
支持函数金宝appclientFasterThanPool
,在本例的末尾列出,返回真正的
如果在客户端上执行多次执行比执行parfor
循环。语法与parfeval
:使用函数句柄作为第一个参数,输出的数量作为第二个参数,然后给出函数所需的所有参数。
首先,创建一个本地ProcessPool
.
P = parpool(“过程”);
使用'Processes'配置文件启动并行池(parpool)…连接到并行池(工人数:6)。
检查它有多快eig
函数运行clientFasterThanPool
金宝app支持功能。创建匿名函数eig
来表示函数调用。
[~, t_client, t_pool] = clientfastthanpool (@(N) eig(randn(N)), 0,500)
T_client = 34.8639
T_pool = 6.9755
并行池比客户机更快地计算答案。分t_client
通过maxNumCompThreads
查找客户机上每个线程所花费的时间。
t_client / maxNumCompThreads
Ans = 5.8107
worker默认是单线程的。结果表明在客户机和池上每个线程所花费的时间是相似的t_pool
是价值的1.5倍t_client / maxNumCompThreads
.的eig
函数不能从多线程中获益。
接下来,检查它有多快陆
函数运行clientFasterThanPool
金宝app支持功能。
[~, t_client, t_pool] = clientfastthanpool (@(N) lu(randn(N)), 0, 500)
T_client = 1.0447
T_pool = 0.5785
如果您的本地计算机有四个或更多内核,那么并行池通常比客户机更快地计算答案。分t_client
通过maxNumCompThreads
找出每个线程所花费的时间。
t_client / maxNumCompThreads
Ans = 0.1741
的值表明,客户机上每个线程花费的时间比池上的时间要少得多t_pool
大概是价值的3倍t_client / maxNumCompThreads
.每个线程使用的计算时间更少,这表明陆
使用多线程。
定义Helper函数
支持函数金宝appclientFasterThanPool
检查客户端上的计算是否比并行池上的计算快。它接受一个函数句柄作为输入fcn
和数量可变的输入参数(In1, in2,…
).clientFasterThanPool
执行Fcn (in1, in2,…)
在客户端和活动的并行池上。作为一个例子,如果您希望进行测试兰特(500)
,你的函数句柄必须是以下形式:
fcn = @(N) rand(N);
然后,用clientFasterThanPool (fcn, 500)
.
函数[result, t_multi, t_single] = clientfastthanpool (fcn,numout,varargin)为输出预分配单元格数组输出= cell(numout);%客户抽搐为I = 1:200如果fcn(varargin{:});其他的[outputs{1:numout}] = fcn(varargin{:});结束结束T_multi = toc;%平行池vararginC = parallel.pool.Constant(varargin);抽搐parforI = 1:200为输出预分配单元格数组输出= cell(numout);如果fcn(varargc . value {:});其他的[outputs{1:numout}] = fcn(varargc . value {:});结束结束T_single = toc;%如果多线程更快,返回true结果= t_single > t_multi;结束
比较parfor
,parfeval
,spmd
使用spmd
能比使用慢一点还是快一点parfor
循环或parfeval
,这取决于计算的类型。开销影响的相对性能parfor
循环,parfeval
,spmd
.
对于一组任务,parfor
而且parfeval
通常比spmd
在这些条件下。
每个任务所花费的计算时间是不确定的。
每个任务所花费的计算时间是不一致的。
每个任务返回的数据都很小。
使用parfeval
当:
你想在后台运行计算。
每个任务都依赖于其他任务。
在本例中,您将检查在使用对象时执行矩阵操作的速度parfor
循环,parfeval
,spmd
.
首先,创建一个并行的流程工作者池p
.
P = parpool(“过程”);
使用'Processes'配置文件启动并行池(parpool)…连接到并行池(工人数:6)。
计算随机矩阵
检查的速度,在随机矩阵可以生成使用parfor
循环,parfeval
,spmd
.设置试验次数(n
)和矩阵大小(对于米
——- - - - - -米
矩阵)。增加试验次数可以改善后期分析中使用的统计数据,但不会影响计算本身。
m =1000;n =
20.;
然后,使用parfor
-循环执行兰特(米)
每个工人一次。每个时间n
试用
parforTime = 0 (n,1);为I = 1:n tic;mats = cell(1,p.NumWorkers);parforN = 1:p。NumWorkers mats{N} = rand(m);结束parforTime(i) = toc;结束
下一步,使用parfeval
执行兰特(米)
每个工人一次。每个时间n
试用
parfevalTime = 0 (n,1);为I = 1:n tic;f(1:p.NumWorkers) = parallel.FevalFuture;为N = 1:p。NumWorkers f(N) = parfeval(@rand,1,m);结束mats = fetchOutputs(f,“UniformOutput”、假)”;parfevalTime(i) = toc;清晰的f结束
最后,使用spmd
执行兰特(米)
每个工人一次。有关工作人员的详细信息以及如何在它们上执行命令spmd
,请参阅在多个数据集上运行单个程序.每个时间n
试用
spmdTime = 0 (n,1);为I = 1:n tic;spmdE = rand(m);结束特征值= {e{:}};spmdTime(i) = toc;结束
使用rmoutliers
去除每次试验中的异常值。然后,用箱线图
比较时间。
%隐藏异常值boxData = routliers ([parforTime parfevalTime spmdTime]);%绘图数据箱线图(boxData“标签”, {“parfor”,“parfeval”,“spmd”},“象征”,”) ylabel (的时间(秒))标题(构造n个随机矩阵(m × m))
通常情况下,spmd
每次计算需要更多的开销parfor
或parfeval
.因此,在这种情况下,使用parfor
循环或parfeval
效率更高。
计算随机矩阵的和
接下来,计算随机矩阵的和。你可以通过使用一个约简变量parfor
-loop,与计算后的和parfeval
,或gplus
与spmd
.同样,设置试验次数(n
)和矩阵大小(对于米
——- - - - - -米
矩阵)。
m =1000;n =
20.;
然后,使用parfor
-循环执行兰特(米)
每个工人一次。用约简变量计算和。每个时间n
试用
parforTime = 0 (n,1);为I = 1:n tic;结果= 0;parforN = 1:p。NumWorkers result =结果+ rand(m);结束parforTime(i) = toc;结束
下一步,使用parfeval
执行兰特(米)
每个工人一次。使用fetchOutputs
在所有矩阵上,然后使用总和
.每个时间n
试用
parfevalTime = 0 (n,1);为I = 1:n tic;f(1:p.NumWorkers) = parallel.FevalFuture;为N = 1:p。NumWorkers f(N) = parfeval(@rand,1,m);结束result = sum(fetchOutputs(f));parfevalTime(i) = toc;清晰的f结束
最后,使用spmd
执行兰特(米)
每个工人一次。使用spmdPlus
对所有矩阵求和。若要只将结果发送给第一个worker,请将可选的target worker参数设置为1
.每个时间n
试用
spmdTime = 0 (n,1);为I = 1:n tic;spmdr = spmdPlus(rand(m), 1);结束结果= r{1};spmdTime(i) = toc;结束
使用rmoutliers
去除每次试验中的异常值。然后,用箱线图
比较时间。
%隐藏异常值boxData = routliers ([parforTime parfevalTime spmdTime]);%绘图数据箱线图(boxData“标签”, {“parfor”,“parfeval”,“spmd”},“象征”,”) ylabel (的时间(秒))标题(n个随机矩阵的和(m × m))
对于这个计算,spmd
明显快于parfor
循环或parfeval
.当你在a中使用约简变量时parfor
的每次迭代的结果parfor
-循环到所有的工人。相比之下,spmd
调用spmdPlus
只需进行一次全局缩减操作,所需开销较少。因此,计算中减少部分的开销为
为spmd
,
为parfor
.