Skip to content

Commit 8b3913d

Browse files
committed
Fix cluster load-balancing hang when n_tasks > n_nodes (#591)
1 parent 946bf56 commit 8b3913d

3 files changed

Lines changed: 15 additions & 2 deletions

File tree

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* `http_config()` gains a `headers` argument, now the primary way to supply HTTP headers (including authentication such as session cookie, bearer token, or API key). `cookie` and `token` are retained as convenience arguments that append `Cookie:` and `Authorization: Bearer` entries to `headers` (thanks @ddl-dkelkhoff, #612).
66
* Reduces overhead for synchronous daemons by using an in-process transport.
77
* Fixes `.handleSimpleError()` appearing in `$stack.trace` on a `miraiError` (regression in mirai 2.7.0).
8+
* Fixes load-balanced parallel functions (e.g. `parLapplyLB()`, `foreach::%dopar%`) hanging on a mirai cluster when there are more tasks than nodes, a regression in mirai 2.5.1 (thanks @manforkr, #591).
89

910
# mirai 2.7.0
1011

R/parallel.R

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ make_cluster <- function(n, url = NULL, remote = NULL, ...) {
8989
daemons(n, dispatcher = FALSE, ..., cleanup = FALSE, .compute = id)
9090
}
9191

92+
`[[<-`(..[[id]], "cvs", cv())
93+
9294
cl <- lapply(seq_len(n), create_node, id = id)
9395
`attributes<-`(cl, list(class = c("miraiCluster", "cluster"), id = id))
9496
}
@@ -121,7 +123,8 @@ sendData.miraiNode <- function(node, data) {
121123
value <- data[["data"]]
122124
tagged <- !is.null(value[["tag"]])
123125
if (tagged) {
124-
cv_reset(envir[["cv"]])
126+
orig_cv <- envir[["cv"]]
127+
`[[<-`(envir, "cv", envir[["cvs"]])
125128
}
126129

127130
m <- mirai(
@@ -131,6 +134,7 @@ sendData.miraiNode <- function(node, data) {
131134
.compute = id
132135
)
133136
if (tagged) {
137+
`[[<-`(envir, "cv", orig_cv)
134138
`[[<-`(m, "tag", value[["tag"]])
135139
}
136140
`[[<-`(node, "mirai", m)
@@ -143,7 +147,7 @@ recvData.miraiNode <- function(node) call_aio(.subset2(node, "mirai"))
143147
#' @exportS3Method parallel::recvOneData
144148
#'
145149
recvOneData.miraiCluster <- function(cl) {
146-
wait(..[[attr(cl, "id")]][["cv"]])
150+
wait(..[[attr(cl, "id")]][["cvs"]])
147151
node <- which.min(lapply(cl, node_unresolved))
148152
m <- .subset2(.subset2(cl, node), "mirai")
149153
list(node = node, value = `class<-`(m, NULL))

tests/tests.R

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,14 @@ connection && {
285285
test_print(cl <- make_cluster(n = 1, url = local_url(), remote = remote_config()))
286286
test_null(stopCluster(cl))
287287
}
288+
# load-balancing across multiple nodes with more tasks than nodes
289+
connection && NOT_CRAN && {
290+
cl <- make_cluster(2)
291+
res <- parLapplyLB(cl, 1:6, function(i) i * 2L)
292+
test_identical(res, as.list(seq(2L, 12L, by = 2L)))
293+
test_identical(parSapplyLB(cl, 1:6, function(i) i + 1L), 2:7)
294+
test_null(stopCluster(cl))
295+
}
288296
# advanced daemons and dispatcher tests
289297
connection && NOT_CRAN && {
290298
test_true(daemons(url = "ws://:0", correctype = 0L, token = TRUE))

0 commit comments

Comments
 (0)