我觉得这很难理解:
cl = makeCluster(rep("localhost", 8), "SOCK")
# This will not work, error: dat not found in the nodes
pmult = function(cl, a, x)
{
mult = function(s) s*x
parLapply(cl, a, mult)
}
scalars = 1:4
dat = rnorm(4)
pmult(cl, scalars, dat)
# This will work
pmult = function(cl, a, x)
{
x
mult = function(s) s*x
parLapply(cl, a, mult)
}
scalars = 1:4
dat = rnorm(4)
pmult(cl, scalars, dat)
# This will work
pmult = function(cl, a, x)
{
mult = function(s, x) s*x
parLapply(cl, a, mult, x)
}
scalars = 1:4
dat = rnorm(4)
pmult(cl, scalars, dat)
由于参数的惰性求值,第一个函数不起作用。但什么是懒惰的评价?执行mult()时,是否需要对x进行求值?第二个是有效的,因为它迫使x被评估。现在最奇怪的事情发生在第三个函数中,什么都没做,但make mult()接收x作为额外的参数,突然一切正常!
另一件事是,如果我不想在调用parLapply()的函数内定义所有变量和函数,我该怎么办?以下肯定不会起作用:
pmult = function(cl)
{
source("a_x_mult.r")
parLapply(cl, a, mult, x)
}
scalars = 1:4
dat = rnorm(4)
pmult(cl, scalars, dat)
我可以将所有这些变量和函数作为参数传递:
f1 = function(i)
{
return(rnorm(i))
}
f2 = function(y)
{
return(f1(y)^2)
}
f3 = function(v)
{
return(v- floor(v) + 100)
}
test = function(cl, f1, f2, f3)
{
x = f2(15)
parLapply(cl, x, f3)
}
test(cl, f1, f2, f3)
或者我可以使用clusterExport(),但是当有很多对象要导出时会很麻烦。还有更好的方法吗?
答案 0 :(得分:5)
要理解这一点,您必须意识到存在与每个功能相关联的环境,该环境取决于功能的创建方式。在脚本中简单创建的函数与全局环境相关联,但由另一个函数创建的函数与创建函数的本地环境相关联。在您的示例中,pmult
创建了mult
,因此与mult
相关联的环境包含正式参数cl
,a
和x
。< / p>
第一种情况的问题是parLapply
对x
一无所知:它只是一个未经评估的形式论证,被序列化为mult
的环境的一部分parLapply
。由于x
在序列化并发送给集群工作人员时未评估mult
,因此当工作人员执行mult
时会导致错误,因为dat
不可用那个背景。换句话说,在mult
评估x
时,为时已晚。
第二种情况有效,因为在x
序列化之前评估了mult
,因此x
的实际值与mult
的环境一起被序列化。如果您了解闭包但不了解懒惰的参数评估,它会做您所期望的。
第三种情况有效,因为您正在为parLapply
处理x
。根本没有任何诡计。
我应警告您,在所有这些情况下,a
正在评估parLapply
并与mult
的环境一起序列化。 parLapply
还将a
拆分为块并将这些块发送给每个工作人员,因此a
环境中mult
的副本完全没有必要。它不会导致错误,但可能会影响性能,因为mult
会发送给每个任务对象中的worker。幸运的是,parLapply
的问题要小得多,因为每个工作者只有一个任务。如果clusterApply
或clusterApplyLB
的任务数等于a
的长度,那将是一个更糟糕的问题。
我在本书的“雪”章节中谈到了与功能和环境有关的一些问题。涉及一些微妙的问题,很容易被烧毁,有时候却没有意识到它已经发生了。
至于你的第二个问题,有各种策略可以将函数导出给工人,但有些人确实使用source
来定义工人的功能,而不是使用clusterExport
。请记住,source
有一个local
参数,用于控制解析表达式的计算位置,您可能需要指定脚本的绝对路径。最后,如果您正在使用远程集群工作程序,如果您没有分布式文件系统,则可能需要将脚本scp到工作程序。
以下是将全局环境中的所有函数导出到集群工作者的简单方法:
ex <- Filter(function(x) is.function(get(x, .GlobalEnv)), ls(.GlobalEnv))
clusterExport(cl, ex)