主要内容

改善parfor性能

可以提高的性能parfor-以各种方式循环。这包括在循环内部并行创建数组;分析parfor循环;切片数组;并在集群上运行之前在本地worker上优化代码。

在哪里创建数组

对象之前的客户端中创建大型数组时parfor-loop,并在循环中访问它,您可能会观察到代码执行缓慢。为了提高性能,告诉每个MATLAB®工作者并行地创建自己的数组或数组的一部分。通过要求每个worker在循环中并行地创建这些数组的自己的副本,可以节省从客户机向worker传输数据的时间。考虑改变在a之前初始化变量的通常做法-循环,避免循环内部不必要的重复。您可能会发现,在循环中并行创建数组可以提高性能。

性能改进取决于不同的因素,包括

  • 数组的大小

  • 创建数组所需的时间

  • 对全部或部分数组的工作者访问

  • 每个worker执行的循环迭代次数

当你考虑转换时,要考虑这个列表中的所有因素循环,parfor循环。有关更多细节,请参见将for-Loops转换为parfor-Loops

作为一种替代方案,请考虑parallel.pool.Constant函数在循环之前在池工作者上建立变量。这些变量在循环结束后仍然保留在worker上,并且对多个变量仍然可用parfor循环。您可以使用parallel.pool.Constant,因为数据只传递给工人一次。

在本例中,首先创建一个大数据集D和执行parfor循环访问D.然后使用D建立一个parallel.pool.Constant对象,该对象允许您通过复制重用数据D每个工人。使用抽搐而且toc并注意它们的区别。

函数constantDemo D = rand(1e7, 1);抽搐I = 1:20 a = 0;parforj = 1:60 a = a + sum(D);结束结束toc tic D = parallel.pool.Constant(D);I = 1:20 b = 0;parforj = 1:60 b = b + sum(D.Value);结束结束toc结束
使用'Processes'配置文件启动并行池(parpool)…连接4个工人。运行时间为63.839702秒。运行时间为10.194815秒。
在第二种情况下,您只发送一次数据。可以提高性能parfor通过使用parallel.pool.Constant对象。

分析parfor循环

你可以分析parfor-循环通过使用抽搐而且toc.您还可以通过使用度量并行池中的工作者之间的数据传输量ticBytes而且tocBytes.注意,这不同于通常意义上使用MATLAB分析器分析MATLAB代码,参见分析代码以提高性能

这个例子计算了一个矩阵的谱半径,并将一个循环到一个parfor循环。测量结果的加速和传输的数据量。

  1. 在MATLAB编辑器中,输入以下内容循环。添加抽搐而且toc测量所消耗的时间。将文件保存为MyForLoop.m

    函数a = MyForLoop(a) tici = 1:200 a(i) = max(abs(eig(rand(a))));结束toc结束
  2. 运行代码,并注意所花费的时间。

    一个= MyForLoop (500);
    运行时间为31.935373秒。

  3. MyForLoop.m,替换循环用parfor循环。添加ticBytes而且tocBytes测量并行池中的工作者之间的数据传输量。将文件保存为MyParforLoop.m

    ticBytes (gcp);parfori = 1:200 a(i) = max(abs(eig(rand(a))));结束tocBytes (gcp)

  4. 运行新代码,然后再运行一次。注意,第一次运行比第二次运行慢,因为必须启动并行池,并且必须使代码对工作者可用。注意第二次运行所花费的时间。

    默认情况下,MATLAB会自动在本地机器上打开一个并行工作池。

    一个= MyParforLoop (500);
    使用“Processes”配置文件启动并行池(parpool)…连接到4个工人. ...bytesessenttoworkers BytesReceivedFromWorkers __________________ ________________________ 1 15340 7024 2 13328 5712 3 13328 5704 4 13328 5728 Total 55324 24168流逝时间为10.760068秒。
    串行运行时间为31.9秒,并行运行时间为10.8秒,这表明该代码得益于转换为parfor循环。

切片数组

如果变量在parfor-循环,然后在parfor-loop,它必须传递给每个评估循环迭代的MATLAB工作者。只有那些在循环中使用的变量才会从客户端工作区传递。但是,如果变量的所有出现都被循环变量索引,那么每个worker只接收到它需要的那部分数组。

例如,您首先运行一个parfor-循环使用切片变量,并测量运行时间。

%切片版本M = 100;N = 1 e6;data = rand(M, N);抽搐parforidx = 1:M out2(idx) = sum(data(idx,:)) ./ N;结束toc
运行时间为2.261504秒。

现在,假设您不小心使用了对该变量的引用数据而不是Nparfor循环。这里的问题是呼叫大小(数据,2)将切片变量转换为广播(非切片)变量。

%意外未切片版本clear M = 100;N = 1 e6;data = rand(M, N);抽搐parforidx = 1:M out2(idx) = sum(data(idx,:)) ./ size(data, 2);结束toc
运行时间为8.369071秒。
注意,偶然广播变量的运行时间更大。

在这种情况下,可以很容易地避免使用的非切片数据,因为结果是一个常数,可以在循环之外计算。通常,在循环开始之前,您可以执行仅依赖于广播数据的计算,因为广播数据不能在循环内部修改。在本例中,计算是微不足道的,并且结果是一个标量结果,因此从循环中取出计算将使您受益。

优化本地工作者和集群工作者

在本地工作者上运行代码可以方便地测试应用程序,而不需要使用集群资源。然而,使用本地工人也有一定的缺点或限制。因为数据的传输不是在网络上发生的,所以本地工作者上的传输行为可能不能说明它通常是如何在网络上发生的。

对于本地工作程序,因为所有的MATLAB工作程序会话都在同一台机器上运行,您可能看不到任何性能改进parfor-循环关于执行时间。这可能取决于许多因素,包括您的计算机有多少处理器和核心。这里的关键点是,集群可能比本地计算机具有更多的可用内核。如果你的代码可以通过MATLAB多线程化,那么提高速度的唯一方法就是使用更多的核心来解决问题,使用集群。

您可以进行实验,看看在循环之前创建数组(如下面的左图所示)是否比让每个worker在循环内部创建自己的数组更快(如右图所示)。

尝试以下在本地运行并行池的示例,并注意每个循环在执行时间上的差异。首先打开一个本地并行池:

parpool (“过程”

运行以下示例,然后再次执行。注意,每种情况的第一次运行都比第二次运行慢,因为必须启动并行池,并且必须使代码对工作者可用。注意第二次运行时,每种情况的运行时间。

抽搐;n = 200;M =魔法(n);R =兰德(n);parfori = 1:n A(i) = sum(M(i,:).*R(n+1-i,:));结束toc
抽搐;n = 200;parfori = 1:n M = magic(n);R =兰德(n);一笔(我)= (M(我:)。* R (n +我,:));结束toc

在远程集群上运行,您可能会发现不同的行为,因为工作人员可以同时创建他们的数组,从而节省传输时间。因此,为本地工作者优化的代码可能不会为集群工作者优化,反之亦然。

另请参阅

相关的话题

Baidu
map