qed*_*qed 3 parallel-processing r snow
这是我觉得难以理解的事情:
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)
Run Code Online (Sandbox Code Playgroud)
由于对参数的惰性求值,第一个函数不起作用.但什么是懒惰的评价?执行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)
Run Code Online (Sandbox Code Playgroud)
我可以将所有这些变量和函数作为参数传递:
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)
Run Code Online (Sandbox Code Playgroud)
或者我可以使用clusterExport(),但是当有很多对象要导出时会很麻烦.有没有更好的办法?
要理解这一点,您必须意识到存在与每个函数相关联的环境,并且该环境取决于函数的创建方式.在脚本中简单创建的函数与全局环境相关联,但由另一个函数创建的函数与创建函数的本地环境相关联.在你的榜样,pmult创建mult,因此与其相关的环境mult包含形式参数cl,a和x.
第一种情况的问题是,parLapply它不知道任何事情x:它只是一个未经评估的形式参数,被序列化为multby 的环境的一部分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)
Run Code Online (Sandbox Code Playgroud)