0%

MATLAB并行工具箱--parfor的使用

最近在使用进行MATLAB进行一些计算的时候因为计算时间实在是太长了(五天。所以开始考虑进行算法优化,就在这时无意间看到了系统的CPU占用率,what?25%哈哈哈哈哈或或或或或或或或,matlab个ZZ。于是想起了parfor这回事,算法用的是动态规划算法,但是在每个递推过程中也要计算$2000 \times 2000$个循环,正好可以用并行计算,perfect,条件允许,直接开始!

要啥简介,直接开干

来看一个简单的不能再简单的例子,我们用for将一个数组乘以2

1
2
3
4
5
n = 1000;
a = rand(n,1);
for i=1:n
a(i) = a(i) * 2;
end

试着跑一下,没什么问题(这要有啥问题可以不活了),看一下运行时间

1
Elapsed time is 0.000034 seconds.

一个n x 1大小的随机数组,然后把其中每个数乘以二,下面就是改成parfor并行计算的

1
2
3
4
5
n = 1000;
a = rand(n,1);
parfor i=1:n
a(i) = a(i) * 2;
end

so easy。这样就改好了,matlab果然易用,同样看一下时间

1
2
Starting parallel pool (parpool) using the 'local' profile ... connected to 4 workers.
Elapsed time is 32.119578 seconds.

WTF,本来想要提高效率的,怎么会变得这么慢,不过看说明似乎干了些别的,再跑一遍试试?

1
Elapsed time is 0.183769 seconds.

看上去时间正常多了嘛不过还是比正常跑慢,怎么回事?首先如果看到上面这些,恭喜,这就是已经开始多核心并行计算了,后面我们来具体分析及使用MATLAB的并行计算。

MATLAB并行计算解释及分析

首先通俗解释一下我们做的事情,比如我们有一堆砖要搬,从A搬到B再搬到C结束。正常情况下,我们有一个小伙子来做这件事,他一次一次把所有砖从A搬到B再搬到C。这就是正常情况下的计算。

但是我们的CPU是多核心的,例如我们是有四个小伙子的,但是在搬砖过程中,这四个小伙子只有一个小伙子在搬砖,另外三个小伙子在围观。。。这怎么可能快嘛,但是我们的小伙子很能干,只要砖不是非常多,工作都能很快完成,时间差距不大,所以也就不需要所有人都上了。

并行计算就是让这几个小伙子都动起来,一起去做这件事,这样才能更加效率的解决工作量比较大的问题。在上面的例子中我们就是这样去做的。

但是

为什么第一次运行这么慢:因为matlab开始并行计算之前,需要进行一些预备工作,这些工作默认是没有开启的,所以在第一次进行并行计算的时候,需要首先进行预备工作,花费一些时间,这样时间长也是理所当然的了。

为什么第二次还是这么慢:虽然在工作中有更多的小伙子来干活,但是在干活中,还需要有一个人去给这些小伙子分配工作,这个分配工作的动作也是需要耗费时间的,这样在工作量非常小的情况下(如上例)这个分配工作的时间可能比做这项工作消耗的时间都要长,这样最终反而计算时间更长。

Parallel Pool 的设置

然后我们来看一下 MATLAB 中关于并行工具箱相关的设置:

(matlab版本使用2015a,其他版本请找相关设置

matlab 中去做这项工作的部分叫做 Parallel pool。在 matlab 的设置界面中或者主界面的左下角的图标处可以进入并行计算工具箱的设置。大概长这样:

并行工具箱设置

最上面的 Clusters 是关于计算的集群的设置,请选择 local (后面看我努力程度是否出个搭建集群的教程吧,非常简单)

Cluster Profile Manager

点击蓝色文字处 Cluster Profile Manager 就可以对本地的这个 Cluster 进行配置了,中间最重要的配置是 Number of workers to start on your local machine 这个决定了有多少个小伙子给你干活,默认情况下,CPU 是几核的就填几。(这一步在实际运行中有一些疑问,核心数or线程数,等待后续进一步验证。)修改后可以顺手点击 Validate 进行验证,几项测试都通过的话就说明配置没有问题,退出设置后点击同样在主界面中左下角菜单中的另外一项 Start parallel pool 就可以打开了,或者在程序中运行到 parfor 时 MATLAB 也会自动开启。

开启之后可以开启系统的任务管理器,查看一下 matlab.exe 有几个,如果 worker 数量为4,那么应该有五个进程在运行,一个是用来进行调度管理的,另外四个是干活的小伙子。可以通过占用内存的不同来区别这两种进程,会有一个占用的内存大小与其他有较大的区别。

Validation Relusts

在并行工具箱的设置中还有两个设置,一个是在遇到需要进行并行计算的语句时自动开启这个 Parallel Pool ,另一个是在一定时间内没有使用并行计算的时候,自动关闭,时间可以自己进行设置。

适用范围&变量说明&技巧

基本使用方法介绍的差不多了,但是哪里有程序第一次能跑起来的。哪种情况才适合使用 parfor 进行并行计算,使用时需要注意哪些问题,怎样才能进一步提高计算速度,我们接着往后看。

适用范围

  • 各部分计算独立:既然是并行计算,所以最基本的要求是 各个部分计算独立 ,也就是说不同小伙子做的工作能独立开,不能互相依赖。你可以让小伙子们同时把砖从A点搬到B点,但是不能让一部分从A搬到B,一部分从B搬到C,因为从B搬到C的工作依赖于另一部分工作,有可能出现没有砖可以搬的情况。

  • 计算量足够大:就如同第一个例子一样,可以看到在进行并行计算的过程中,不管是多个小伙子的工作分配或者是和工作分配者和小伙子之间的数据发送与接收,都需要消耗一定量的时间,这样情况下如果工作量本身规模不大,这些消耗已经比并行计算带来的时间优势完全抹杀掉了,所以只有在计算量极大的情况下才适用。并且计算量越大,并行计算带来的时间优势越明显。

变量分类

MATLAB 对 parfor 使用中的变量分为五类,如下图:

parfor_vartypes

  • loop Variable : 循环变量,就是简单的 for 循环中的变量,上图中的 i。
  • Sliced Variable : 某数组中分发给每个 worker 的变量,或者多个 worker 存储到同一个数组中的变量,要求不同 worker 接触的变量不能重复交叉的现象,并且下标连续,不能使用例如 2*i 这类下标。
  • Broadcast Variable : 需要分发给每个 worker 使用的同一个数据,这个数据对于每个 worker 来说是只读不写的。
  • Reduction Variable : 在不同循环中对同一个变量进行叠加的计算,注意这个叠加的意思不仅仅代表加法,任何符合交换律的运算都可以,比如加减乘除,当然不能混用,因为混用之后就不符合交换律了,这样才能在不同 worker 计算完成时间不确定的情况下保证计算的正确性。也即,计算顺序不影响计算结果。
  • Temporary Variable : 临时变量,在每个 worker 运行过程中创建并销毁的变量,不同 worker 之间使用自己的临时变量,互相独立。

如果在使用过程中报错无法运算,可以查看一下自己使用的变量和上面五类对应一下属于哪类。所有涉及到的变量 必须 属于这五类中的某一类,并符合相关的规则。所以如果出错不能运行的话,慢慢对照查一下吧。

技巧

如何进一步提高计算速度

  • 影响速度的主要因素:计算依旧是使用 CPU 去跑的,经过不同电脑的几次试验,主要影响因素是 核心数量 ,主频当然是有影响的,但是差距不大,核心数越多速度越快。所以尽可能的发动你的交际技巧去找个多核电脑吧。

  • 尽量减少 worker 传输的数据量:在进行计算时,管理这些小伙子工作的人要把工作内容一项一项分配下去,例如工作需要的数据,这样不可避免的会出现很多数据交换,在 MATLAB 中这些数据被称为 Broadcast Variables ,非常形象的一个名字,这些数据需要分发到每个 worker 的手中。这里我们需要尽量减少这类变量的大小,只传必要的数据过去,看上去似乎不多,但是在巨量的循环次数面前,浪费的每一点时间都可以被放大到很大的程度。

关于worker数量

根据我自己查到的各种资料,都是说 worker 数量与 CPU 核心数量相同,但是在我多个电脑多次实际运行过程中发现这样 CPU 占用率一直不是100%,所以目前我在本机运行的时候使用的 worker 数量都是线程数,这点有待进行进一步考证。因为占用率是一方面,也要考虑计算的实际速度。