R语言多任务处理与并行运算包——foreach

28次阅读
没有评论

共计 2038 个字符,预计需要花费 6 分钟才能阅读完成。

相信大部分 R 语言初学者,在刚开始入门之处,都曾被告诫在处理多重复任务时,尽量不要使用显式的 for 循环,而要尽可能的使用 R 语言内置的 apply 组函数,这样可以极大地提高代码运行效率。
但是实际上除了内的 apply 组函数之外,你还有另外一个更好地选择,就是利用一些支持并行运算的扩展包,来发挥本地计算机的多和计算优势。
本篇要讲解的包是 foreach 包,这是一个支持在 R 语言中调用多进程功能的第三方包,之前在对比显式循环、矢量化函数以及多进程在数据抓取的效率一文中,曾经演示过具体的代码。
library(“foreach”)
library(“doParallel”)
foreach 包执行任务的核心理念与传统的 apply 组函数基本一致,都是与 split – apply – combine 一致的流程,不过 foreach 比传统 apply 组函数的优越之处在于,它可以通过调用操作系统的多核运行性能来执行并行任务,这样特别是对于 I / O 密集型任务而言,可以大大节省代码执行效率。
foreach(…,            # 待输入的参数       .combine,        # 结果返回后执行的数据合并操作 (c 代表合并为向量,list 代表合并为列表,rbind 代表合并为数据框)       .packages=NULL,  # 在多进程共享的程序包(仅对于非系统安装包必备)      .export=NULL,    # 未在当前环境中定义的数据对象       .verbose=FALSE   #是否打印运行信息       )
以上函数中,第 1 个参数是必备参数,即必须有输入参数,结果默认返回 list。
foreach 函数用于定义执行多进程任务的函数,任务的执行则需要使用 %do%/%dopar% 函数,前者执行的是普通的单进程任务(与 apply 组函数一样),后者则可以执行多进程任务。
接下来我们演示一遍整个多进程任务的过程:
首先定义一个执行函数:
library(“httr”) library(“jsonlite”)
library(“magrittr”)
GETPDF <-  function(i){ url<-“https://index.toutiao.com/api/report”  headers<-c(            “Host”=”index.toutiao.com”,     “User-Agent”=”Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36”  )  payload <-list(“page”=1,”size”=12)    payload[[“page”]]=i    web <- GET(url,add_headers(.headers = headers),query = payload)    content <- web %>% content(as=”text”,encoding=”UTF-8″) %>% fromJSON() %>% `[[`(9)  }
2、执行多进程函数
方案 1——使用 %do% 函数执行普通的向量运算
library(“doParallel”)      # 加载 doParallel 包用于之后注册进程
library(“foreach”)         #导入 foreach 包
system.time({ cl<- makeCluster(4)        registerDoParallel(cl)       #进行进程注册  mydata1 <- foreach(
              i=1:16,          # 输入等待请求的参数              .combine=rbind,  # 返回结果的整合              .packages = c(“httr”, “jsonlite”,”magrittr”) 
              #多个进程共享的系统环境  ) %dopar% GETPDF(i)  stopCluster(cl)}) 用户 系统 流逝 0.08 0.01 2.18
方案 2——使用 %dopar% 函数执行多进程的运算
system.time({ cl<-makeCluster(4)  registerDoParallel(cl)  mydata2 <- foreach(i=1:16,.combine=rbind) %do% GETPDF(i)  }) 用户 系统 流逝 0.39 0.03 4.53
因为 %do% 操作是单进程的,因而即便启动多进程环境也是徒劳。
DT::datatable(mydata1)

R 语言多任务处理与并行运算包——foreach

可以看到,%dopar% 操作比 %do% 操作仅仅节省了 0.04 秒左右,但是鉴于抓包的请求频率比较高,这样多进程所节省的时间效率感知不够明显。
system.time(mydata3 <- plyr::ldply(1:16,GETPDF)) 用户 系统 流逝 0.32 0.00 4.54
整体时间效率比较:
ldply > %do% >  %dopar%4.54  > 4.53 >  2.18
从时间效率上来看,的确节省了将近 50% 的时间。
正文完
 0