我正在开发一个包来执行R中的分布式计算(在github上的RHadoop项目下的rmr)。我试图让用户尽可能透明,只需将计算继续在其他机器上的另一个解释器中,就好像它在同一台机器上一样。像
这样的东西lapply(my.list, my.function)
其中每次调用my.function
原则上都可以在集群中的不同节点上进行,因此需要单独的解释器。我正在使用save
和load
对取得一定程度的成功,但我希望有一个解决方案可以在所有可能的情况下运行,而不仅仅是在一大堆用例中。
无论my.function
做什么,无论它在哪里定义,无论它引用的是什么其他对象和包,我都希望确保如果它在本地工作,它也可以远程工作,包括加载必要的包裹和一切。 save
和load
保存对象列表并加载文件resp。来自或来自特定环境。我想找到或写一些东西来保存和加载必要环境中的所有必要对象,以便在my.function
的每个元素上评估my.list
将在本地和远程具有相同的语义。
以前是否已经完成,我应该检查的任何套餐,还有其他任何建议吗?我认为这是rmr中最难的技术问题,您将为OSS项目贡献您的解决方案。
答案 0 :(得分:4)
通常save
和load
应该按照您的意愿工作:当保存一个函数时(实际上,它是一个被保存的“闭包”),也会保存定义它的环境。如果该函数被定义为包的一部分,则会保存对该包的引用,并在load
看到引用时再次重新加载包。 (如果包没有命名空间,则在保存时会收到警告)。
唯一的问题应该是全球环境。在那里,还保存了一个引用,但这不会保存全局环境中的所有变量,因此您必须明确保存它们。
保存其他环境,包括其内容,然后递归保存父环境(除非它是如上所述的包或globalenv)。
请注意,saveRDS
和serialize
替代方案提供了更多控制:您可以提供在保存环境时调用的refhook
函数。然后,您可以执行任何要存储环境的操作并返回字符串ID。加载时,会调用类似的refhook来从该字符串id重新创建环境。但是,您仍然没有被要求保存全球环境。
e <- new.env() # parent is global env
e$foo <- 42
ee <- new.env(parent=e)
ee$bar <- 13
f <- local(function() foo+bar, ee)
f() # foo+bar = 55
b <- serialize(f, NULL) # Gives you the serialized bytes
g <- unserialize(b) # Loads from the bytes
g() # 55
# It created new environments...
!identical(environment(g), environment(f))
希望这有点帮助。
祝你好运rmr
!
答案 1 :(得分:1)
在进一步考虑this question后,似乎答案可能对您的问题有用。如果您在保存环境方面遇到与OP相同的问题,那么Gabor's answer可能会帮助您走上正轨。但是,如果基本的序列化和环境保存是问题,我的(通常不太复杂)的答案可能有帮助 - 通过as.list()
转换为列表,然后以通常的方式序列化,或考虑通过JSON序列化;我最喜欢的包是RJSONIO
。