主要内容

之间做出选择spmdparfor,parfeval

并行代码通信

要并行运行计算,可以使用parforparfevalparfevalOnAll,或spmd.每个构造都依赖于不同的并行编程概念。如果您要求工作人员在整个计算过程中进行通信,请使用parfevalparfevalOnAll,或spmd

  • 使用parfevalparfevalOnAll如果您的代码可以拆分为一组任务,其中每个任务可以依赖于其他任务的输出。

  • 使用spmd如果在计算过程中需要工作人员之间的通信。

计算与parfeval最好用图表来表示,类似于带块的看板。一般来说,结果是在计算完成后从worker那里收集的。类的执行可以收集结果parfeval使用操作afterEach毕竟.您通常在进一步的计算中使用这些结果。

计算与spmd最好用流程图来表示,类似于瀑布工作流。执行一个池工作人员spmd语句被称为实验室。结果可以在计算过程中从实验室收集。有时,实验室在完成计算之前必须与其他实验室进行交流。

如果你不确定,问自己以下问题:在我的通信并行代码中,每个计算是否可以在没有任何工作者之间的通信的情况下完成?如果是,请使用parfeval.否则,使用spmd

同步和异步工作

当你在parforparfeval,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;结束

比较parforparfeval,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每次计算需要更多的开销parforparfeval.因此,在这种情况下,使用parfor循环或parfeval效率更高。

计算随机矩阵的和

接下来,计算随机矩阵的和。你可以通过使用一个约简变量parfor-loop,与计算后的和parfeval,或gplusspmd.同样,设置试验次数(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只需进行一次全局缩减操作,所需开销较少。因此,计算中减少部分的开销为 O n 2 spmd, O n 2 parfor

另请参阅

||

相关的话题