主要内容

改进parfor表演

你可以改进的性能parfor-以各种方式进行循环。这包括在循环内并行创建数组;分析parfor-循环;切片阵列;以及在集群上运行之前在本地工作者上优化代码。

在何处创建阵列

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

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

  • 数组的大小

  • 创建阵列所需的时间

  • 工人访问全部或部分阵列

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

考虑在考虑转换时列表中的所有因素-循环到parfor-循环。有关更多详细信息,请参阅将for循环转换为parfor循环

作为另一种选择,考虑并行池常数函数在循环之前在池辅助对象上建立变量。这些变量在循环完成后保留在辅助对象上,并可用于多个应用程序parfor循环。您可以使用它来提高性能并行池常数,因为数据只传输一次给工人。

在本例中,首先创建一个大数据集D和执行parfor-循环存取D.那么你用D建立一个并行池常数对象,它允许您通过复制来重用数据D给每个工人。使用抽搐toc对于每种情况,请注意差异。

作用康斯坦德莫D=兰德(1e7,1);泰克I = 1:20 a = 0;parfora = a + sum(D);结束结束toc tic D = parallel.pool.Constant(D);I = 1:20 b = 0;parforj=1:60 b=b+和(D.值);结束结束toc结束
>>constantDemo使用“本地”配置文件启动并行池(parpool)…连接到4个工作进程。运行时间为63.839702秒。运行时间为10.194815秒。
在第二种情况下,只发送一次数据。可以提高parfor使用并行池常数对象

轮廓parfor循环

你可以对parfor-loop通过测量使用时所经过的时间抽搐toc.您还可以通过使用ticBytestocBytes。请注意,这与使用MATLAB profiler分析通常意义上的MATLAB代码不同,请参阅分析代码以提高性能

这个例子计算一个矩阵的光谱半径,并转换-绕成一圈parfor循环。测量由此产生的加速和传输的数据量。

  1. 在MATLAB编辑器中,输入以下内容循环。添加抽搐toc要测量经过的时间,请将文件另存为MyForLoop.m

    作用a=MyForLoop(a)tici = 1:20 00 a(i) = max(abs(eig(rand(a))));结束toc结束
  2. 运行代码,并记下经过的时间。

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

  3. 在里面MyForLoop.m,更换循环用parfor循环。添加ticBytestocBytes测量并行池中工作线程之间传输的数据量。将文件另存为MyParforLoop.m

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

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

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

    一个= MyParforLoop (500);
    使用“本地”配置文件启动并行池(parpool)…连接到4个工人…通过从工人处接收的TessentToWorkers…Uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu11534070242 13328 5712 13328 5704 13328总时间为10.068秒。
    串行运行时间为31.9秒,并行运行时间为10.8秒,这表明此代码从转换为parfor循环。

切片数组

如果变量在aparfor-循环,然后在parfor-循环时,必须将其传递给每个评估循环迭代的MATLAB工作人员。只有循环中使用的变量才能从客户端工作区传递。但是,如果变量的所有引用都由循环变量索引,则每个工作人员只接收其所需数组的一部分。

例如,首先运行parfor-loop使用一个切片的变量并测量经过的时间。

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

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

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

在这种情况下,您可以很容易地避免不切片地使用数据,因为结果是一个常量,可以在循环外部计算。通常,您可以在循环开始之前执行仅依赖于广播数据的计算,因为广播数据不能在循环内部修改。在这种情况下,计算很简单,结果是标量结果,因此您可以从循环中去掉计算。

优化本地与集群工人

在本地工作程序上运行代码可能会为测试应用程序提供便利,而无需使用群集资源。但是,使用本地工作程序存在某些缺点或限制。由于数据传输不会通过网络进行,因此本地工作程序上的传输行为可能无法指示它是如何运行的病态通常发生在网络上。

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

您可以进行实验,看看是否在循环之前创建数组更快(如下图所示),而不是让每个工作人员在循环中创建自己的数组(如图所示)。

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

帕尔普(“本地”

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

tic;n=200;M=magic(n);R=rand(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

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

另请参阅

相关话题