如何解决完成多个并行运行的R作业后如何运行另一个Rscript?
我需要如何运行脚本的安排是首先使用rstudioapi::jobRunScript()
函数并行运行4个R脚本。并行运行的每个脚本不会从任何环境导入任何内容,而是将创建的数据帧导出到全局环境。 我的第5个R脚本基于并行运行的4个R脚本创建的数据帧,并且第5个R脚本也在控制台中运行。如果有一种方法可以在头四个R脚本并行运行后在后台在后台运行第5个脚本,而不是在控制台中运行,那会更好。我还试图减少整个过程的总运行时间。
尽管我能够弄清楚如何并行运行前四个R脚本,但是我的任务并未完全完成,因为我找不到如何触发第五个R脚本运行的方法。希望大家能在这里帮助我
解决方法
我喜欢这个有点太开放了。尽管rstudioapi
绝对可以用于运行并行任务,但是它不是很通用,也不能提供非常有用的输出。 parallel
Universe在R中很好地实现了几个包,这些包提供了一个更简单,更好的接口来实现此目的。这里有3个选项,它们也允许从不同的文件“输出”某些东西。
package =并行
使用并行包,我们可以非常简单地实现此目的。只需创建一个将要获取文件的向量,并在每个线程中执行source
。当它们运行时,主进程将锁定,但是如果您无论如何都要等待它们完成,这并没有多大关系。
library(parallel)
ncpu <- detectCores()
cl <- makeCluster(ncpu)
# full path to file that should execute
files <- c(...)
# use an lapply in parallel.
result <- parLapply(cl,files,source)
# Remember to close the cluster
stopCluster(cl)
# If anything is returned this can now be used.
作为一个附带说明,一些软件包与parallel
软件包(基于snow
软件包构建)具有相似的接口,因此这是一个很好的基础。
package = foreach
parallel
软件包的替代方案是foreach
软件包,它提供类似于for-loop
接口的内容,简化了接口,同时提供了更大的灵活性,并自动导入了必要的库和变量(尽管手动执行此操作比较安全)。foreach
软件包确实依赖parallel
和doParallel
软件包来建立集群。
library(parallel)
library(doParallel)
library(foreach)
ncpu <- detectCores()
cl <- makeCluster(ncpu)
files <- c(...)
registerDoParallel(cl)
# Run parallel using foreach
# remember %dopar% for parallel. %do% for sequential.
result <- foreach(file = files,.combine = list,.multicombine = TRUE) %dopar% {
source(file)
# Add any code before or after source.
}
# Stop cluster
stopCluster(cl)
# Do more stuff. Result holds any result returned by foreach.
虽然确实添加了几行代码,但是.combine
,.packages
和.export
使得一个非常简单的界面可以在R中使用并行计算。
package = future
现在,这是要使用的较为罕见的软件包之一。 future
提供的并行接口比parallel
和foreach
都更灵活,允许异步并行编程。但是,该实现似乎有些艰巨,而我下面提供的示例只是对可能的实现进行了摸索。
还值得一提的是,尽管future
软件包确实提供了运行代码所需的功能和软件包的自动导入,但经验使我意识到,这仅限于任何调用的第一级深度(有时更少),因此仍然需要导出。
尽管foreach
依赖于parallel
(或类似)来启动集群,但是foreach
会使用所有可用的内核来启动自己。对plan(multiprocess)
的简单调用将启动多核会话。
library(future)
files <- c(...)
# Start multiprocess session
plan(multiprocess)
# Simple wrapper function,so we can iterate over the files variable easier
source_future <- function(file)
future(file)
results <- lapply(files,source_future)
# Do some calculations in the meantime
print('hello world,I am running while waiting for the futures to finish')
# Force waiting for the futures to finish
resolve(results)
# Extract any result from the futures
results <- values(results)
# Clean up the process (close down clusters)
plan(sequential)
# Run some more code.
现在乍一看似乎很繁重,但是一般的机制是:
- 致电
plan(multiprocess)
- 使用
future
(或%<-%
,我将不介绍)执行某些功能 - 如果还有更多代码要运行,请执行其他操作,而这不取决于进程
- 使用
resolve
等待结果,该结果可用于列表(或环境)中的单个期货或多个期货。 - 在列表(或环境)中对单个期货使用
value
或对多个期货使用values
收集结果 - 使用
future
清理在plan(sequential)
环境中运行的所有群集 - 继续使用取决于您的期货结果的代码。
我相信这3个软件包为任何用户需要与之交互的多处理的每个必要元素(至少在CPU上)提供了接口。其他软件包提供了替代接口,而对于异步,我仅知道future
和promises
。总的来说,我建议大多数用户在进行异步编程时要非常小心,因为与同步并行编程相比,这可能会引起一整套不那么频繁的问题。
我希望这可以为rstudioapi
接口提供一个替代方案(非常严格),我可以肯定的是,它绝不打算由用户自己用于并行编程,而是更有可能用于执行任务例如通过界面本身并行构建软件包。
您可以将promises
与future
结合使用:promises::promise_all
后跟promises::then
可以等待上一个futures
的完成,然后再启动最后一个{后台进程。
在作业在后台运行时,您可以控制控制台。
library(future)
library(promises)
plan(multisession)
# Job1
fJob1<- future({
# Simulate a short duration job
Sys.sleep(3)
cat('Job1 done \n')
})
# Job2
fJob2<- future({
# Simulate a medium duration job
Sys.sleep(6)
cat('Job2 done \n')
})
# Job3
fJob3<- future({
# Simulate a long duration job
Sys.sleep(10)
cat('Job3 done \n')
})
# last Job
runLastJob <- function(res) {
cat('Last job launched \n')
# launch here script for last job
}
# Cancel last Job
cancelLastJob <- function(res) {
cat('Last job not launched \n')
}
# Wait for all jobs to be completed and launch last job
p_wait_all <- promises::promise_all(fJob1,fJob2,fJob3 )
promises::then(p_wait_all,onFulfilled = runLastJob,onRejected = cancelLastJob)
Job1 done
Job2 done
Job3 done
Last job launched
,
我不知道这对您当前的情况有多大的适应性,但是这是一种使四件事并行运行,获取它们的返回值然后触发第五个表达式/函数的方法。
前提是使用foreach (string pageName in _pages)
{
Task.Run(async () => { Sync_pageName() }); // where pageName will be the items from list.
}
运行单个文件。这实际上运行的是callr::r_bg
,而不是文件,因此我会修改这些文件的外观,例如 。
我将编写一个辅助脚本,该脚本旨在模仿您的四个脚本之一。我猜想您也希望能够正常获取该源代码(直接运行而不是作为函数运行),因此我将生成脚本文件,以便它“知道”它是源文件还是直接运行(基于Rscript detect if R script is being called/sourced from another script)。 (如果您知道function
,则类似于python的python
技巧。)
名为if __name__ == "__main__"
的辅助脚本。
somescript.R
作为演示,如果在控制台上somefunc <- function(seconds) {
# put the contents of a script file in this function,and have
# it return() the data you need back in the calling environment
Sys.sleep(seconds)
return(mtcars[sample(nrow(mtcars),2),1:3])
}
if (sys.nframe() == 0L) {
# if we're here,the script is being Rscript'd,not source'd
somefunc(3)
}
,则此 just 定义函数(如果需要,可以定义多个函数),它不会在最后一个{ {1}}块:
source
但是如果我在终端中使用if
来运行它,
system.time(source("~/StackOverflow/14182669/somescript.R"))
# # <--- no output,it did not return a sample from mtcars
# user system elapsed
# 0 0 0 # <--- no time passed
回到前提。像上面的Rscript
一样重写脚本文件,而不是四个“脚本”。如果操作正确,则可以$ time /c/R/R-4.0.2/bin/x64/Rscript somescript.R
mpg cyl disp
Merc 280C 17.8 6 167.6
Mazda RX4 Wag 21.0 6 160.0
real 0m3.394s # <--- 3 second sleep
user 0m0.000s
sys 0m0.015s
和somescript.R
进行不同的意图。
我将使用这个脚本四次,而不是四个脚本。这是我们要自动化的手动操作:
Rscript
我们可以使用
实现自动化source
现在运行第五个函数/脚本。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。