openmp并行编程_学习R语言:简单并行计算

本文介绍了在R语言中使用snow包和OpenMP进行并行计算,探讨了共同外链问题的解决,并分析了并行计算的性能考虑,包括开销来源、任务分配策略。同时,文章提供了调试并行代码的方法和相关资源。
摘要由CSDN通过智能技术生成

本文内容来自《R 语言编程艺术》(The Art of R Programming),有部分修改

不要对并行抱有太高期望,很多情况下并行版本实际上比串行版本运行速度更慢。

共同外链问题

mutual outlink

对于 n x n 矩阵

sum = 0
for i = 0...n-1
for j = i+1...n-1
for k = 0...n-1 sum = sum + a[i][k] * a[j][k]
mean = sum / (n*(n-1)/2)

snow 包简介

定义问题

上述问题的源代码

mtl  function(ichunk, m) {
n ncol(m)
matches 0for (i in ichunk) {if (i < n) {
rowi m[i,]
matches matches + sum(m[(i+1):n,] %*% rowi)
}
}return (matches)
}
mutlinks  function(cls, m) {
n nrow(m)
nc length(cls)
ichunks split(1:n, 1:nc)
counts clusterApply(cls, ichunks, mtl, m)do.call(sum, counts) / (n*(n-1)/2)
}

其中 split() 函数用于将矩阵分块

split(1:4, 1:2)
$`1`
[1] 1 3

$`2`
[1] 2 4

运行 snow 代码

加载 snow 包

library(snow)

创建 snow 集群,在本机开启两个新进程,称为 worker。原有 R 进程称为 manager。

所有 worker 形成一个集群 cluster。

snow 使用 分布/聚合 (scatter/gather) 范式:

  • manager 将数据分割为若干块,打包发送给 worker

  • 每个 worker 处理自己的分块

  • manager 从 worker 收集结果 (聚合阶段),并将其组合成应用需要的正确形式

cl  makeCluster(
type="SOCK",c("localhost", "localhost")
)
cl
socket cluster with 2 nodes on host ‘localhost’

建立相关的邻接矩阵

testm  matrix(sample(0:1,16,
replace=TRUE
),
nrow=4
)
testm
     [,1] [,2] [,3] [,4]
[1,] 0 0 0 1
[2,] 0 0 0 0
[3,] 1 0 1 1
[4,] 1 1 1 0

在创建的集群上针对邻接矩阵运算代码

mutlinks(cl, testm)
[1] 0.5

借助于 C

扩展案例:利用 OpenMP 解决共同外链问题

注:以下代码在 Ubuntu 20.04 上运行

#include #include 
int tot;

int procpairs(int i, int *m, int n) {
int j, k, sum = 0;
for(int j = i + 1; j < n; j++) {
for(int k = 0; k < n; k++) {
sum += m[n*k + i] * m[n*k + j];
}
}
return sum;
}

void mutlinks(int *m, int *n, double *mlmean) {
int nval = *n;
tot = 0;
#pragma omp parallel {
int mysum = 0;
int me = omp_get_thread_num();
int nth = omp_get_num_threads();
for(int i=me; i < nval; i += nth) {
mysum += procpairs(i, m, nval);
}
#pragma omp atomic tot += mysum;
}
int divisor = nval * (nval - 1)/2;
*mlmean = ((float) tot) / divisor;
}

运行 OpenMP 代码

R CMD SHLIB romp.c -fopenmp
gcc -I"/opt/R/4.0.3/lib/R/include" -DNDEBUG   -I/usr/local/include   -fpic  -g -O2  -c romp.c -o romp.o
gcc -shared -L/opt/R/4.0.3/lib/R/lib -L/usr/local/lib -o romp.so romp.o -fopenmp -L/opt/R/4.0.3/lib/R/lib -lR
dyn.load("romp.so")
Sys.setenv(OMP_NUM_THREADS=4)
n 1000
m matrix(sample(0:1, n^2, replace=TRUE), nrow=n)system.time(z.C("mutlinks", as.integer(m), as.integer(n), result=double(1)))
   user  system elapsed
1.428 0.010 1.439
z$result
[1] 250.5263

普遍的性能考虑

开销的主要来源

共享内存的机器

内存访问

缓存

潜伏期 (latency),尤其是主机和设备之间的传输

网络计算机群系统

网络传输

snow 中传输前将对象转为字符串 (序列化?)

简单并行程序,以及那些不简单的

“简单并行” embarrassingly parallel

静态和动态任务分配

静态任务分配

for (i = me; i < nval; i += nth) {
mysum += procpairs(i, m, nval);
}

动态任务分配

int nexti = 0;
// ...skip...for( ; myi < n;) {
#pragma omp critical {
nexti += 1;
myi = nexti;
}
if (myi <n) {
mysum += procpairs(myi, m, nval)
// ...skip... }
}
// ...skip..

注意:因为有 critical 指令,动态分配可能比静态分配的版本要慢得多

软件炼金术:将一般的问题转化为简单并行问题

利用统计的性质,可以将某些非简单并行问题转化为简单并行问题

共同外链问题,w 个 worker 对链接矩阵 m 进行操作:

  • 将 m 的行分成 w 个块

  • 让每个 worker 计算对应的小块中所有定点配对的平均外链数

  • 对所有 worker 返回的结果取平均值

调试 R 语言并行计算的代码

非常困难

调试在 worker 上运行的函数

尝试使用 message() 函数,或者使用 cat() 将信息写入到文件中

参考

学习 R 语言系列文章:

《快速入门》

《向量》

《矩阵和数组》

《列表》

《数据框》

《因子和表》

《编程结构》

《数学运算与模拟》

《面向对象编程》

《输入与输出》

《字符串操作》

《基础绘图》

《R与其他语言的接口》

本文代码请访问如下项目:

https://github.com/perillaroc/the-art-of-r-programming


d56bea797ff56bdbfa49495c1f82a813.png

题图由 Carlos Carlos Alberto 在 Pixabay 上发布。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值