我认为您可以为此使用setTimeLimit。
快速演示:
setTimeLimit(elapsed = 2)
Sys.sleep(999)
# Error in Sys.sleep(999) : reached elapsed time limit
setTimeLimit(elapsed = Inf)
(请务必注意,当您不再希望中断时,您应该返回时间限制设置。)
我的“复杂算法”会随机休眠。那些随机长度是
set.seed(42)
sleeps <- sample(10, size=5)
sleeps
# [1] 1 5 10 8 2
我将设置一个 6 秒的任意限制,超过此限制睡眠将被中断,我们将不会获得任何返回值。这应该会中断第三个和第四个元素。
iter <- 5
result <- list()
for (i in seq_len(iter)) {
result[[i]] <- tryCatch({
setTimeLimit(elapsed = 6)
Sys.sleep(sleeps[[i]])
setTimeLimit(elapsed = Inf)
c(iter = i, slp = sleeps[[i]])
}, error = function(e) NULL)
}
result
# [[1]]
# iter slp
# 1 1
# [[2]]
# iter slp
# 2 5
# [[3]]
# NULL
# [[4]]
# NULL
# [[5]]
# iter slp
# 5 2
如果你有不同的“睡眠”并且你最终得到一个比你需要的更短的对象,只需附加它:
result <- c(result, vector("list", 5 - length(result)))
我会稍微改进一下,有几件事:
- 以这种方式填充
result时,我更喜欢lapply而不是for循环;和
- 由于复杂的算法可能由于其他原因而失败,如果我的睡眠提前失败,那么时间限制将不会被重置,所以我将使用
on.exit,它确保在其外壳退出时调用一个函数,无论是由于错误与否。
result <- lapply(seq_len(iter), function(i) {
setTimeLimit(elapsed = 6)
on.exit(setTimeLimit(elapsed = Inf), add = TRUE)
tryCatch({
Sys.sleep(sleeps[i])
c(iter = i, slp = sleeps[i])
}, error = function(e) NULL)
})
result
# [[1]]
# iter slp
# 1 1
# [[2]]
# iter slp
# 2 5
# [[3]]
# NULL
# [[4]]
# NULL
# [[5]]
# iter slp
# 5 2
在这种情况下,result 的长度为 5,因为 lapply 每次迭代都会返回一些内容。 (lapply 的使用对于 R 来说是惯用的,它的效率通常在 apply 和 map-like 方法中,不像其他语言通过文字 for 循环实现真正的速度。)
(顺便说一句:除了on.exit 逻辑,我也可以使用tryCatch(..., finally=setTimeLimit(elapsed=Inf))。)
on.exit 逻辑的替代方法是在要限制的执行块内 中使用setTimeLimit(.., transient=TRUE)。这将使这段代码
result <- lapply(seq_len(iter), function(i) {
tryCatch({
setTimeLimit(elapsed = 6, transient = TRUE)
Sys.sleep(sleeps[i])
c(iter = i, slp = sleeps[i])
},
error = function(e) NULL)
})
这样做的一个好处是,无论受限代码块是否成功/中断,一旦完成,限制就会立即解除,因此无意中将其留在原位的风险较小。