2013-02-06 74 views
4

如果能够在R中创建一个函数,这个函数可能会阻塞,直到资源被定义或被赋予适当的值,这将是非常有用的。我知道R是单线程的,但我希望mc能够提供帮助。但是,阻止和等待R

library(parallel) 
f = function() { 
    while(!exists('a')) Sys.sleep(1); 
    print('success!') 
} 
d = mcparallel(f()) 
a = 1 
mccollect(d) 

无限期地挂起。是否有任何有效的解决方法,还是我必须研究完全不同的模式/不同的语言才能实现此类目的?

+0

不同的进程不共享他们的内存,所以你的子进程在主进程中不能检测到变量'a'的创建。 – wush978

回答

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,R可能不是你想要的语言,但它可能适用于轻量级应用程序。


我曾在RStudio之前测试的代码,但它似乎工作,它的方式,是从成功中难以区分是失败。无论如何,它基本上不会等待过程。例如,这应该永远不会完成,但它确实(仅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) 
+0

我不知道为什么,但这不适合我;试图在scan()中包括what ='character'并发送一个没有空格的字符串,以防这些扫描造成问题,但无济于事。任何想法为什么这可能是?我能想到的只有版本;我在x64系统上运行R-2.15.1。 – tresbot

+0

@tresbot我不明白。该代码仅适用于RStudio Server。我无法让它在其他地方工作。 – nograpes

+0

@tresbot好的,我明白了。代码基本上是失败的。正如你所指出的那样,你需要'what ='character'',并且你不需要消息中的空格,但是你还需要以'\ n'结尾。 – nograpes

5

另一个黑客,很少有可取的地方,是在?socketConnection使用套接字在两个进程之间通信的底部相适应的例子。我们做的分叉处理的服务器(服务器必须首先启动,所以不可能是互动的过程),并把它的道路上...

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 

这将有一个更合理的费用l如果进程是独立的而不是分叉的,如在MPI作业中可以使用Rmpi包在节点之间进行通信。

+0

有没有办法让服务器主动侦听命令?我最初试图做的是: 'con1 < - socketConnection(port = 6011,server = TRUE,open =“r”); i = 0; (i == 0) {if(a < - readLines(con1))eval(parse(text = a))}; 关闭(con1);' 但这似乎导致死锁,只要我创建一个客户端连接。 – tresbot

2

我不知道使用并行的方式,但tcltk实用程序以与常规R事件循环并行或背景显示的方式运行。您可以使用tclTaskSchedule功能从tcltk2包做一些像你上面的循环:

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(或者大约一秒钟内),那么'成功!'将被打印到屏幕上(并且它将停止检查)。

请注意,这是使用并行的替代品。很明显,tcltk和并行软件包并不能很好地结合在一起(看起来这已经在R devel中修复并修补了,所以这可能在R版本2.15.3之后并行工作)。所以如果你也使用并行包来处理其他事情,请小心使用它。如果并行只是您正在尝试的一种选择,而您并未将其用于其他事情,那么此方法应该可以正常工作。