如何解决R:如何将 foreach 用于预先指定的重复次数,例如在 while 循环中
library(foreach)
library(doMC)
myfun <- function(threshold){
val <- rnorm(1,mean = 0,sd = 1)
if(val > threshold){
stop("bad")
}else return(val)
}
results <- vector("list",length = 10)
parallel_fun <- function(reps,threshold){
registerDoMC(cores = 48)
results = foreach (j = 1:reps,.combine = rbind) %dopar% {
myfun(threshold)
}
}
> parallel_fun(reps = 10,threshold = 0)
Error in { : task 1 Failed - "bad"
以上是一个简单的、可重现的示例。我想并行化 myfun
以获得总共 reps = 10
次复制。如果生成的 myfun
大于某个 val
,threshold
可能会停止。在这种情况下,我想停止运行 myfun
而不是让它返回 val
。最后,我希望我的 results
有 10 个 vals
大于某个 threshold
。因此,我认为在这里使用 while 循环可能更合适,因为我想让它一直运行,直到我有 10 个满足 threshold
的值。是否可以将 foreach
重新用于并行化 while 循环?
解决方法
控制流程
通常不鼓励对控制流使用异常。理想情况下,
使用已经做你想做的功能
在此特定示例中,您正在模拟截断正态分布。因此,您可以使用 truncnorm 包中的 truncnorm
函数。
重写函数
或者,重写 myfun
以始终返回正确的值:
myfun = function(threshold){
repeat{
val = rnorm(1,1)
if(val <= threshold)
break
}
val
}
这只是可能的变体之一。在这里,我使用自定义 do-while
构造。
请注意,根据阈值,可能会发生大量或潜在无限次数的迭代,因此请谨慎行事,要么设置最大迭代次数,要么进行一些初步检查,如果 threshold
不在所讨论函数的最大范围,最好是两者。
有了这个,您应该能够像现在一样轻松地运行 foreach
。
编写包装器
如果您无法控制 myfun
,则需要构造包装器,构造可能与上面的函数几乎相同:
wrap_myfun = function(threshold){
repeat{
val = try(myfun(threshold))
if(is.numeric(val))
break
}
val
}
跟踪迭代:
如果您需要跟踪生成所述数字所需的迭代次数,您可以将 repeat
重写为 for
循环或仅添加计数器和另一个选项:>
wrap_myfun = function(threshold,.maxiter=10^9,.default=NA){
iter = 1
repeat{
val = try(myfun(threshold))
if(is.numeric(val))
break
if(iter >= .maxiter){
val = .default
break
}
iter = iter + 1
}
list("value"=val,"iterations"=iter)
}
或者,您可以使用`stop("最大迭代次数达到"),而不是分配默认值。这取决于问题的严重程度。
通过这种方式,您已将所有逻辑移到数据生成函数中,而不必管理在 foreach
中实现的队列。负载应该在内核之间平均分配(超过某些迭代的潜在随机长计算时间,但这是您无法影响的)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。