主要内容

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

从桌面扩展到集群

在本地计算机上开发并行 MATLAB® 代码并扩展到集群。

集群提供更多的计算资源来加速和分配您的计算。您可以在本地计算机上以交互方式并行运行代码,然后在集群上运行,而无需更改代码。当您在本地计算机上完成代码原型设计后,您可以使用批处理作业将计算卸载到集群。因此,您可以关闭 MATLAB 并稍后检索结果。

开发您的算法

首先在本地计算机上对算法进行原型设计。该示例使用整数分解作为示例问题。这是一个计算密集型的问题,其中分解的复杂性随着数字的数量级而增加。您使用一个简单的算法来分解一系列整数。

创建一个 64 位精度的素数向量,并随机将素数对相乘以获得较大的合数。创建一个数组来存储每次分解的结果。本示例中以下每个部分的代码可能需要 20 多分钟。为了加快速度,可以使用更少的素数(例如 2^19)来减少工作量。使用 2^21 运行以查看最佳最终图。

primeNumbers = primes(uint64(2^21));
compositeNumbers = primeNumbers.*primeNumbers(randperm(numel(primeNumbers)));
factors = zeros(numel(primeNumbers),2);

使用循环对每个合数进行因式分解,并测量计算所需的时间。

tic;
for idx = 1:numel(compositeNumbers)
    factors(idx,:) = factor(compositeNumbers(idx));
end
toc
Elapsed time is 684.464556 seconds.

在本地并行池上运行代码

Parallel Computing Toolbox™ 使您能够通过在并行池中运行多个工作单元来扩展工作流。前一个 for 循环中的迭代是独立的,因此您可以使用 parfor 循环将迭代分配给多个工作单元。只需将 for 循环转换为 parfor 循环。然后,运行代码并测量总体计算时间。代码在并行池中运行,无需进一步更改,然后工作单元将您的计算发送回本地工作区。由于工作量分布在多个工作单元身上,因此计算时间较短。

tic;
parfor idx = 1:numel(compositeNumbers)
    factors(idx,:) = factor(compositeNumbers(idx));
end
toc
Elapsed time is 144.550358 seconds.

当您使用 parfor 并且有 Parallel Computing Toolbox 时,MATLAB 会自动启动一个并行工作单元池。并行池需要一些时间才能启动。此示例显示池已启动的第二次运行。

默认配置文件是 'Processes'。您可以在 MATLAB 主页选项卡的并行> 选择并行环境中检查此配置文件是否设置为默认配置文件。启用此配置文件后,MATLAB 会在您的计算机上为并行池创建工作单元。当您使用 'Processes' 配置文件时,MATLAB 默认会启动与计算机中的物理核一样多的工作单元,直至达到 'Processes' 配置文件中设置的限制。您可以使用并行设置来控制并行行为。在“MATLAB 主页”选项卡中,选择并行>并行设置

为了衡量工作单元数量带来的加速,请多次运行相同的代码,并限制最大工作单元数量。首先,定义每次运行的工作单元数量,最多为池中的工作单元数量,并创建一个数组来存储每次测试的结果。

numWorkers = [1 2 4 6];
tLocal = zeros(size(numWorkers));

使用循环遍历最大工作单元数量,并运行前面的代码。要限制工作单元的数量,请使用第二个输入参量 parfor

for w = 1:numel(numWorkers)
    tic;
    parfor (idx = 1:numel(compositeNumbers), numWorkers(w))
        factors(idx,:) = factor(compositeNumbers(idx));
    end
    tLocal(w) = toc;
end

通过计算单个工作单元的计算时间与每个最大工作单元数的计算时间之间的比率来计算加速比。为了直观地了解计算量如何随着工作单元数量的增加而增加,请绘制加速比与工作单元数量的关系图。观察发现加速效果随着工作单元数量的增加而增加。然而,由于并行化带来的开销,扩展并不完美。

f = figure;
speedup = tLocal(1)./tLocal;
plot(numWorkers, speedup);
title('Speedup with the number of workers');
xlabel('Number of workers');
xticks(numWorkers);
ylabel('Speedup');

完成计算后,删除当前并行池,以便为集群创建一个新的并行池。您可以使用 gcp 函数获取当前并行池。

delete(gcp);

设置集群

如果您的计算任务对于本地计算机来说太大或太慢,您可以将计算卸载到现场或云中的集群。在运行接下来部分之前,您必须获得集群的访问权限。在 MATLAB 主页选项卡上,转到并行 > 发现集群以查明您是否已经可以使用 MATLAB Parallel Server™ 访问集群。有关详细信息,请参阅发现集群

Discover Clusters dialog box, asking "Where do you want to look for MATLAB Parallel Server clusters?", with the options "On your network" and "On MathWorks Cloud Center".

如果您无权访问集群,则必须先配置对集群的访问权限,然后才能运行下一部分。在 MATLAB 中,您可以直接从 MATLAB Desktop 在云服务(如 Amazon® AWS®)中创建集群。在主页选项卡上,在 Parallel 菜单中,选择 Create and Manage Clusters。在 Cluster Profile Manager 中,点击 Create Cloud Cluster。如需进一步了解如何向云端扩展,请参阅 云中心入门指南。要了解有关扩展到网络中集群的选项的更多信息,请参阅 安装 (MATLAB Parallel Server)

设置集群配置文件后,您可以在并行 > 创建和管理集群中修改其属性。有关详细信息,请参阅发现集群并使用集群配置文件。下图显示了集群配置文件管理器中的集群配置文件:

The Cluster Profile Manager, showing the Create, Manage Profile, Validate, Cloud, and Help sections at the top, and details of avaialbe cluster profiles below.

在集群并行池上运行您的代码

如果您希望默认在集群中运行并行函数,请在并行> 选择并行环境中将您的集群配置文件设置为默认:

The parallel environment menu shows a list of avaible parallel environments, which a check mark next to the MyCluster parallel environment.

您还可以使用编程方法来指定您的集群。为此,通过在 parpool 命令中指定集群配置文件的名称来启动集群中的并行池。在以下代码中,将 MyCluster 替换为您的集群配置文件的名称。还可以使用第二个输入参量指定工作单元的数量。

parpool('MyCluster',64);
Starting parallel pool (parpool) using the 'MyCluster' profile ...
connected to 64 workers.

与前面一样,通过多次运行相同的代码并限制最大工作单元数量来测量工作单元数量的加速。由于本示例中的集群比本地设置允许更多的工作单元,因此 numWorkers 可以容纳更多值。如果运行此代码,parfor 循环现在在集群中运行。

numWorkers = [1 2 4 6 16 32 64];
tCluster = zeros(size(numWorkers));

for w = 1:numel(numWorkers)
    tic;
    parfor (idx = 1:numel(compositeNumbers), numWorkers(w))
        factors(idx,:) = factor(compositeNumbers(idx));
    end
    tCluster(w) = toc;
end

计算加速比,并将其与工作单元数量绘制成图,以直观地了解计算量如何随着工作单元数量的增加而扩大。将结果与本地设置的结果进行比较。观察发现加速效果随着工作单元数量的增加而增加。然而,由于并行化带来的开销,扩展并不完美。

figure(f);
hold on
speedup = tCluster(1)./tCluster;
plot(numWorkers, speedup);
title('Speedup with the number of workers');
xlabel('Number of workers');
xticks(numWorkers(2:end));
ylabel('Speedup');

完成计算后,删除当前并行池。

delete(gcp);

使用 batch 卸载和扩展您的计算

完成原型设计和交互运行后,您可以使用批处理作业通过批处理来卸载后台长时间运行的计算的执行。计算发生在集群中,您可以关闭 MATLAB 并稍后检索结果。

使用 batch 函数向您的集群提交批处理作业。您可以将算法的内容放在脚本中,然后使用 batch 函数提交。例如,脚本 myParallelAlgorithm 根据本示例中显示的整数分解问题执行一个简单的基准测试。该脚本测量了具有不同数量工作单元的几个问题复杂性的计算时间。

请注意,如果您使用 batch 发送脚本文件,MATLAB 会将所有工作区变量传输到集群,即使您的脚本不使用它们。如果您的工作空间较大,则会对数据传输时间产生负面影响。最佳做法是将脚本转换为函数文件以避免这种通信开销。您只需在脚本开头添加一个函数行即可完成此操作。要了解如何将 myParallelAlgorithm 转换为函数,请参阅 myParallelAlgorithmFcn

以下代码将 myParallelAlgorithmFcn 作为批处理作业提交。myParallelAlgorithmFcn 返回两个输出参量 numWorkerstime,您必须将 2 指定为输出数值输入参量。因为代码需要用于 parfor 循环的并行池,所以使用 'Pool' 中的 batch 名称-值对来指定工作单元的数量。集群使用额外的工作单元来运行该函数本身。默认情况下,batch 会将集群中工作单元的当前文件夹更改为 MATLAB 客户端的当前文件夹。它对于控制当前文件夹很有用。例如,如果集群使用不同的文件系统,因此路径不同,例如从 Windows® 客户端计算机提交到 Linux® 集群。将名称-值对 'CurrentFolder' 设置为您选择的文件夹,或设置为 '.' 以避免更改工作单元的文件夹。

totalNumberOfWorkers = 65;
cluster = parcluster('MyCluster');
job = batch(cluster,'myParallelAlgorithmFcn',2,'Pool',totalNumberOfWorkers-1,'CurrentFolder','.');

要在作业提交后监控作业状态,请在并行> 监控作业中打开作业监控程序。当集群中开始计算时,作业的状态变为 running

The Job Monitor displays a single job that contains one task with the description "Batch job running function myParallelAlgorithmFcn", and state "Running".

作业提交后您可以关闭 MATLAB。当您再次打开 MATLAB 时,作业监控程序会为您跟踪该作业,如果您右键点击它,您就可以与其进行交互。例如,要检索作业对象,请选择显示详细信息;要将批处理作业的输出传输到工作区,请选择获取输出

Job monitor shows a job running on MyCluster profile

或者,如果您想阻止 MATLAB 直到作业完成,请在作业对象上使用 wait 函数。

wait(job);

要从集群传输函数的输出,请使用 fetchOutputs 函数。

outputs = fetchOutputs(job);
numWorkers = outputs{1};
time = outputs{2};

检索结果后,您可以使用它们在本地计算机上进行计算。计算加速比,并根据工作单元数量绘制图。因为代码针对不同问题复杂性运行分解,所以您会得到每个级别的图。您可以看到,对于每个问题的复杂性,加速会随着工作单元数量的增加而增加,直到额外工作单元的开销大于并行化带来的性能增益。随着问题复杂性的增加,您可以在大量工作单元上实现更好的加速,因为与并行化相关的开销不那么重要。

figure
speedup = time(1,:)./time;
plot(numWorkers,speedup);
legend('Problem complexity 1','Problem complexity 2','Problem complexity 3','Problem complexity 4','Location','northwest');
title('Speedup vs complexity');
xlabel('Number of workers');
xticks(numWorkers(2:end));
ylabel('Speedup');

另请参阅

| | |

主题