能够在R中创建一个可以阻止直到定义资源或给定适当值的函数对我来说非常有用。我知道R是单线程的,但我曾希望mc能够提供帮助。然而,
library(parallel)
f = function() {
while(!exists('a')) Sys.sleep(1);
print('success!')
}
d = mcparallel(f())
a = 1
mccollect(d)
无限期挂起。有没有有效的解决方法,或者我是否需要研究完全不同的模式/不同的语言来实现某种类型的工作?
答案 0 :(得分:7)
另一个很难推荐它的黑客是调整使用套接字在两个进程之间进行通信的?socketConnection
底部的示例。我们将forked进程设置为服务器(必须首先启动服务器,因此不能成为交互式进程)并将其发送到路上...
f <- function() {
system.time({
con1 <- socketConnection(port = 6011, server = TRUE, open="r")
while (isIncomplete(con1))
readLines(con1)
close(con1)
})
}
d <- mcparallel(f())
然后我们只与它沟通一次,并收集结果
con2 <- socketConnection(Sys.info()["nodename"], port = 6011)
writeLines("ok", con2)
close(con2)
mccollect(d)
这表明我执行后续命令时分叉进程等了一秒半
> mccollect(d)
$`28975`
user system elapsed
0.000 0.000 1.515
如果进程是分离的而不是分叉的,那么这将是一种更合理的感觉,就像在MPI作业中一样,可以使用Rmpi包在节点之间进行通信。
答案 1 :(得分:5)
我甚至不知道可以分叉这样的进程。在玩了一下之后,我找到了sendChildStdin
函数,你应该检查一下。它至少是一种向子进程发出信号的方式。这是一个例子:
f<- function () {
message<-scan(n = 1, quiet = TRUE, what='character')
return(message)
}
p <- mcparallel(f())
a <- 1
# The message shouldn't contain spaces and should end with a newline.
parallel:::sendChildStdin(p, "created\n")
mccollect(p)[[1]]
[1] "created"
别误会我的意思;如果你要深入研究这些东西,R可能不是你想要的语言,但它可能适用于轻型应用程序。
我之前在RStudio中测试了代码,尽管它似乎有效,但它的失败方式与成功无法区分。无论如何,它基本上不等待scan
进程。例如,这应该永远不会完成,但它确实(仅在RStudio中)
f<- function () {
message<-scan(n = 1, quiet = TRUE, what='character')
return(message)
}
p <- mcparallel(f())
# parallel:::sendChildStdin(p, "created\n")
mccollect(p)[[1]]
# character(0)
答案 2 :(得分:2)
我不知道使用并行的方法,但tcltk实用程序以与常规R事件循环并行或背景的方式运行。您可以使用tcltk2包中的tclTaskSchedule
函数执行类似上述循环的操作:
library(tcltk)
library(tcltk2)
tclTaskSchedule(1000, if( exists('a') ) {
tclTaskChange('WaitForA', redo=FALSE)
cat('Success!\n\n')
}, id='WaitForA', redo=TRUE )
现在您可以在R中执行其他操作(假设a
尚不存在),并且在后台,上面将每隔1秒检查一次a
。创建a
后(或大约一秒钟内),然后成功!&#39;将被打印到屏幕上(它将停止检查)。
请注意,这是使用parallel的替代品。显然,tcltk和并行软件包不能很好地协同工作(看起来这已经在R devel中修复并修补,所以这可能在R版本2.15.3之后并行运行)。因此,如果您还使用并行包进行其他操作,请小心使用它。如果parallel只是你正在尝试的一个选项而你没有将它用于其他事情,那么这个方法应该可以正常工作。