Main Content

本页采用了机器翻译。点击此处可查看英文原文。

spmdparforparfeval 之间选择

要并行运行计算,您可以使用 spmdparforparfevalparfevalOnAll。每种构造都依赖于不同的并行编程概念。

何时使用 parfor

如果您有一个具有慢速循环迭代或许多循环迭代的 for 循环,则 parfor 循环会很有用。每次迭代必须独立于所有其他迭代。有关何时使用 parfor 的更多帮助,请参阅 决定何时使用 parfor

何时使用 spmd

运行通信并行代码

如果在计算过程中需要细粒度的工作进程到工作进程通信和工作进程之间的协作,请使用 spmdparforparfevalparfevalOnAll 不允许工作进程之间的通信。使用 spmd 的计算可以涉及使用 spmdSendspmdReceivespmdSendReceive 函数的工作进程之间的通信。

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

在分布式数组上运行并行和定制代码

如果您的计算涉及分布在各个工作进程上的大型数组,请使用 spmd。您可以对所有工作进程执行同时计算,也可以对特定工作进程执行定制计算。

当工作进程运行 spmd 代码块时,每个工作进程被分配一个唯一的索引,即 spmdIndex。这使您可以指定仅在某些工作进程和分布式数组的目标部分上运行的代码。

同步和异步工作

parforparfevalspmd 之间进行选择时,请考虑您的计算是否需要与客户端同步。

parforspmd 需要同步,因此阻止您在 MATLAB® 客户端上运行任何新的计算。parfeval 不需要同步,因此您可以继续使用客户端。

使用其他功能

spmdparfeval 具有其他功能,您可以在提交计算后使用。

  • 使用 spmd,您可以收集 spmd 语句内部计算的结果,而无需将结果传输到客户端。从客户端以 Composite 对象的形式访问 spmd 语句内分配的变量的值。有关详细信息,请参阅使用复合材料访问工作进程变量

  • 当您提交 parfeval 任务时,MATLAB 会安排该任务异步运行,并在提交的任务运行完成之前返回 Future 对象。Future 对象代表 MATLAB 已安排的任务。您可以通过不同的方式与 Future 对象进行交互:

    • 使用 fetchNext 检索可用的结果或检查结果是否准备就绪。

    • 使用 cancel 函数停止运行 parfeval 计算。

    • 在客户端的其他计算中使用 Future 对象。

比较 parforparfevalspmd 的性能

使用 spmd 可能比使用 parfor 循环或 parfeval 更慢或更快,具体取决于计算的类型。开销会影响 parfor 循环、parfevalspmd 的相对性能。

对于一组任务,在以下条件下,parforparfeval 通常比 spmd 表现更好:

  • 每个任务所花费的计算时间是不确定的。

  • 每个任务所花费的计算时间并不一致。

  • 每个任务返回的数据很少。

在以下情况下使用 parfeval

  • 您想在后台运行计算。

  • 每个任务都依赖于其他任务。

在此示例中,您将检查使用 parfor 循环、parfevalspmd 时软件执行矩阵运算的速度。

首先,创建一个进程工作进程并行池 p

p = parpool("Processes");
Starting parallel pool (parpool) using the 'Processes' profile ...
Connected to parallel pool with 6 workers.

计算随机矩阵

检查软件使用 parfor 循环、parfevalspmd 生成随机矩阵的速度。设置试验次数(n)和矩阵大小(对于 m×m 矩阵)。增加试验次数可以改善后续分析中使用的统计数据,但不会影响计算本身。

m = 1500;
n = 20;

然后,使用 parfor 循环为每个工作进程执行一次 rand(m)。对每次 n 试验进行计时。

parforTime = zeros(n,1);
for i = 1:n
    tic;
    mats = cell(1,p.NumWorkers);
    parfor N = 1:p.NumWorkers
      mats{N} = rand(m);
    end
    parforTime(i) = toc;
end

接下来,使用 parfeval 为每个工作进程执行一次 rand(m)。对每次 n 试验进行计时。

parfevalTime = zeros(n,1);
for i = 1:n
    tic;
    f(1:p.NumWorkers) = parallel.FevalFuture;
    for N = 1:p.NumWorkers
      f(N) = parfeval(@rand,1,m);
    end
    mats = fetchOutputs(f);
    parfevalTime(i) = toc;
    clear f
end

最后,使用 spmd 为每个工作进程执行一次 rand(m)。您可以使用 spmdCat 将每个工作进程上的 mat 的值连接成数组 mats 并将其存储在工作进程 1 上。有关工作进程的详细信息以及如何使用 spmd 对它们执行命令,请参阅 在多个数据集上运行单个程序。对每次 n 试验进行计时。

spmdTime = zeros(n,1);
for i = 1:n
    tic;
    spmd
        mat = rand(m);
        mats = spmdCat({mat}, 1, 1);
    end
    allMats = mats{1};
    spmdTime(i) = toc;
end

使用 rmoutliers 从每次试验中删除异常值。然后,使用 boxplot 来比较时间。

% Hide outliers
boxData = rmoutliers([parforTime parfevalTime spmdTime]);

% Plot data
boxplot(boxData, 'labels',{'parfor','parfeval','spmd'}, 'Symbol','')
ylabel('Time (seconds)')
title('Make n Random Matrices (m-by-m)')

通常,spmd 每次评估所需的开销比 parforparfeval 要大。因此,在这种情况下,使用 parfor 循环或 parfeval 更有效。

计算随机矩阵的和

接下来,计算随机矩阵的和。您可以通过使用带有 parfor 循环的归约变量、带有 parfeval 的计算后的总和或带有 spmdspmdPlus 来实现此目的。再次设置试验次数(n)和矩阵大小(对于 m×m 矩阵)。

m = 1500;
n = 20;

然后,使用 parfor 循环为每个工作进程执行一次 rand(m)。使用归约变量来计算总和。对每次 n 试验进行计时。

parforTime = zeros(n,1);
for i = 1:n
    tic;
    result = 0;
    parfor N = 1:p.NumWorkers
      result = result + rand(m);
    end
    parforTime(i) = toc;
end

接下来,使用 parfeval 为每个工作进程执行一次 rand(m)。使用 fetchOutputs 获取所有矩阵,然后使用 sum。对每次 n 试验进行计时。

parfevalTime = zeros(n,1);
for i = 1:n
    tic;
    f(1:p.NumWorkers) = parallel.FevalFuture;
    for N = 1:p.NumWorkers
      f(N) = parfeval(@rand,1,m);
    end
    result = sum(fetchOutputs(f));
    parfevalTime(i) = toc;
    clear f
end

最后,使用 spmd 为每个工作进程执行一次 rand(m)。使用 spmdPlus 对所有矩阵求和。要将结果仅发送给第一个工作进程,请将可选的目标工作进程参量设置为 1。对每次 n 试验进行计时。

spmdTime = zeros(n,1);
for i = 1:n
    tic;
    spmd
        r = spmdPlus(rand(m), 1);
    end
    result = r{1};
    spmdTime(i) = toc;
end

使用 rmoutliers 从每次试验中删除异常值。然后,使用 boxplot 来比较时间。

% Hide outliers
boxData = rmoutliers([parforTime parfevalTime spmdTime]);

% Plot data
boxplot(boxData, 'labels',{'parfor','parfeval','spmd'}, 'Symbol','')
ylabel('Time (seconds)')
title('Sum of n Random Matrices (m-by-m)')

对于这个计算,spmdparfor 循环或 parfeval 更快。当在 parfor 循环中使用归约变量时,每个工作进程都会执行本地缩减,然后将其部分结果发送回客户端以计算最终结果。

相比之下,spmd 仅调用一次 spmdPlus 来执行全局缩减操作,需要的开销较少。因此,计算减少部分的开销对于 spmd 来说是 O(n2),对于 parfor 来说是 O(mn2)

另请参阅

| |

相关主题