本文只是对于多核CPU运行单一程序的优化,以及简单的GPU运算(非CUDA)
部分内容引自:http://blog.sina.com.cn/s/blog_6b597bfb01018wa5.html
并行化计算通过client-workers体系,client负责分发任务,workers(数量等于CPU核数)负责完成任务
1、使用parfor循环
parfor循环把变量分为五类:循环变量*、广播变量、临时变量、分段变量以及简约变量。
举例如下:a = 100;
s = 0;
parfor k = 1 : 100 % k为循环变量if a > 10 % 广播变量
b = 10; % 临时变量
endc(k) = k; % 分段变量,输入属性
d = 1e3; % 临时变量
s = s + k; % 简约变量
end循环变量:即代码中的k。
广播变量:该变量不是由worker产生,而是当client把任务分配给worker时传给worker的,每个worker都会接收到此类变量。
临时变量:在worker中产生,worker执行完任务之后clear掉,也不会传递给client的变量。
分段变量
:这是parfor中最为重要的变量,可以具有输入和输出两类属性。
简约变量:循环执行的先后次序无关的操作在MATLAB中叫简约循环,也能在MATLAB中并行化。。
- 并行开启(执行parfor语句自动开启)
delete(gcp('nocreate')); % 确保没有并行池运行
parpool ; %打开并行池
parpool(2); %打开特定大小的池
p = gcp; delete(p); %删除当前并行池
- 首先使用for循环写好对于程序,在进行如下判断
若要并行,必须满足以下2个条件之一:每次循环之间是相互独立的;循环执行完之后的结果和循环执行的先后次序无关。
- 加速要点
- 并行运算变量不需要预先分配内存空间;因为一旦在parfor之前预分配内存了,该分段变量就具备了输入属性,已在client中生成了,client再将其分段传递给不同的worker,这会消耗额外的时间。所以,我们的原则是:分段变量能不增加输入属性就不增加。(只针对并行运算)
一般编程注意
1、多使用列向量。
2、a(a>0.5) = 0; % 逻辑索引、a(find(a>0.5)) = 0; % 数值索引、毫无疑问,前者的代码执行速度更快。
3、对于通信算法SNR仿真,可以使用break语句,在性能符合要求的SNR跳出。
-
直接将for改为parfor,根据提示修改程序
一般被赋值变量的索引应该从1开始且顺序存储,被调用广播变量等也尽量从1开始。(经验)2、简单的GPU加速
- 将需要GPU运算的变量使用gpuArray()转换写入GPU,在GPU计算完成后使用gather()将需要收集的变量读入Matlab工 作区内存空间进行下一步操作。(考虑到内存读写,此方法只对某些方法加速效果良好)
- 使用arrayfun()函数
1、例:d = arrayfun(@myfunction,a,b,c);
,myfunction为当前调用函数,在GPU进行处理,a、b、c为输入gpuArray类型参数(可以按照函数要求添加多个参数,每个参数维度一致;如果c不是gpuArray类型,函数运行开始将自动转为gpuArray)。
2、使用gather可以收集d。不支持数组输出(标量输入输出)。
非gpuArray情况
1、支持数组输出(如输入参数a、b、c分别为1、2、3;输出为[1,2],'UniformOutput’设置为‘false’),输出为cell类型;对于cell类型,通过()访问cell数组时访问到的是cell单元,通过{}访问cell数组时访问到的是cell单元储存的内容。
2、同理数组输入也需要使用cell类型,或者struct结构体;
3、可以使用num2cell(matrix,dismension),将输入矩阵转为cell类型,将dismension维度合并,如A为3x2矩阵,2维度,转换后B为3x1cell类型,B{1} = A(1,:) 。
4、对于结构体类型,例a(1).x = [1 2];a(2).x = [ 2 3];以a输入,a.x读取即可。
%% 定义函数
function a = add(b,c)
a = b + c;
end
%% arrayfun 三种函数使用方法
l = @(b,c) b+c;
d = arrayfun(@add,[1 2 3],[2 3 4]) ;
d = arrayfun(@(b,c) b+c,[1 2 3],[2 3 4]) ;
d = arrayfun(l,[1 2 3],[2 3 4]) ;
%%gpuArray
d = arrayfun(l,gpuArray([1 2 3]),gpuArray([2 3 4])) ;(输入输出均为标量)
3、batch批处理
- 主要用于集群等,简单语句说明一下,未深入了解
job = batch('mywave'); %批处理,不阻塞当前程序继续运行,使用默认集群
%可以设置'Pool'参数,定义使用并行池数量,需要先关闭之前开启的并行池
wait(job) %强行阻塞等待
diary(job); %打印子程序的打印信息Command Window Output
load(job,'A'); %加载job中变量到当前工作区,原始数据类型
delete(job); %删除数据
clear job; %删除工作空间
job_function = batch(fcn,N,{x,y,z,...}); %批处理函数,fcn为函数句柄,N为输出参数数量,x,y,z,...为输入参数
%可以设置'Pool'参数,定义使用并行池数量,需要先关闭之前开启的并行池
wait(job_function);
if(job_function.State == 'finished')
job_function_out = fetchOutputs(job_function); % 加载返回数据到工作区,cell类型
class(job_function_out{1}) %返回数据类型
end