前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >47-R编程(九:多线程操作之parallel)

47-R编程(九:多线程操作之parallel)

作者头像
北野茶缸子
发布2021-12-17 09:10:53
9340
发布2021-12-17 09:10:53
举报
文章被收录于专栏:北野茶缸子的专栏

参考:https://blog.csdn.net/weixin_41929524/article/details/81707053https://www.jianshu.com/p/3882ea7b9cc9

R的并行化计算其实没有改变其整个并行环境,而是先启动N个附属进程,然后将数据分割成N块在N个核上进行运行,等待附属进程结束返回结果。

有的时候,我们使用R 总是感觉速度不够快,而实际上有很大一部分的程序是可以通过多线程进行并行运算的。可以参见:https://www.yuque.com/mugpeng/linux/keu2nd

使用包 parallel 。它其实就是将本来的apply 家族替换成了perApply,但采用了多线程。

1)常用函数

代码语言:javascript
复制
detectCores() 检查当前的可用核数
clusterExport() 配置当前环境
makeCluster() 分配核数
stopCluster() 关闭集群
parLapply() lapply()函数的并行版本

我们首先可以通过detectCores() 获得当前电脑可用核心数:

代码语言:javascript
复制
detectCores()
4

比如我可怜的小mac 只有4个心脏。

接着我们配置一下,初始化分配给R 的核心数:

代码语言:javascript
复制
no_cores <- detectCores() - 2
cl <- makeCluster(no_cores)

接着我们就可以使用lapply()函数的并行版本parLapply。

我们可以先比较一下lapply 和parLapply 的运行速度:

代码语言:javascript
复制
> system.time(lapply(1:1000000, function(x) c(x, x**2, x**3)))
 用户  系统  流逝 
1.672 0.025 1.777 
> system.time(parLapply(cl, 1:1000000, function(x) c(x, x**2, x**3)))
 用户  系统  流逝 
0.447 0.086 1.785 

需要注意,使用parLapply 函数时,需要指定参数cl。

2)一般操作

参考:https://www.bioinfo-scrounger.com/archives/577/

其一般操作就是先在开头添加分配核数的语句makeCluster(),接下来调用parApply 方法,最后结束以后,需要使用stopCluster(cl) 结束并行。

3)变量作用域

局部调用

在调用时,分配的核心相当于新的环境。我们必须要在parAapply函数内部重新调用值或者加载包。比如在函数中加载:

代码语言:javascript
复制
library(parallel)
cl <- makeCluster(3)

x = c()
for (i in 1:600){
  x[i] <- paste(letters[sample(1:26, 3)], collapse='')
}

test_function <- function(x) {
  library(stringr)
  return(str_to_upper(x))
}

result <- parLapply(cl, x, test_function)
final <- do.call('c',result)

stopCluster(cl)

如果是在外部加载,则会报错:

代码语言:javascript
复制
library(stringr)
test_function <- function(x) {
  return(str_to_upper(x))
}

result <- parLapply(cl, x, test_function)

# error
Error in checkForRemoteErrors(val) : 
  3 nodes produced errors; first error: 没有"str_to_upper"这个函数

同样,如果是在函数中调用了外部的变量也是:

代码语言:javascript
复制
a <- 2
test_function <- function(x) {
  return(x[a])
}

result <- parLapply(cl, x, test_function)

# output
Error in checkForRemoteErrors(val) : 
  3 nodes produced errors; first error: 找不到对象'a'

对于环境中的变量,可以使用clusterExport 加载,而包可以使用clusterEvalQ 加载:

代码语言:javascript
复制
clusterExport(cl, "a")
clusterEvalQ(cl, library(stringr))

全局配置

我们还可以直接在开启核心时就进行配置:

代码语言:javascript
复制
cl <- makeCluster(3, type="FORK") # mac & linux

Parallel Socket Cluster (PSOCK) # WIN

这一选项从而当你并行运行的时候可以包含所有环境变量。

但对于包中的函数,还是需要专门的使用clusterEvalQ 加载。

4)小建议

  • 运行完毕后释放内存

stopCluster(cl)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-10-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 北野茶缸子 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1)常用函数
  • 2)一般操作
  • 3)变量作用域
    • 局部调用
      • 全局配置
      • 4)小建议
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档