Почему parLapplyLB на самом деле не балансирует нагрузку?
Я тестирую функцию parLapplyLB()
, чтобы понять, что она делает для балансировки нагрузки. Но я не вижу никакого равновесия. Например,
cl <- parallel::makeCluster(2)
system.time(
parallel::parLapplyLB(cl, 1:4, function(y) {
if (y == 1) {
Sys.sleep(3)
} else {
Sys.sleep(0.5)
}}))
## user system elapsed
## 0.004 0.009 3.511
parallel::stopCluster(cl)
Если бы он действительно балансировал нагрузку, то первое задание (задание 1), которое спит в течение 3 секунд, было бы на первом узле, а остальные три задания (задания 2:4) спали бы в общей сложности 1,5 секунды на другом узле. В общей сложности системное время должно составлять всего 3 секунды.
Вместо этого я думаю, что задания 1 и 2 даны узлу 1 и заданиям 3 и 4 даны узлу 2. Это приводит к тому, что общее время составляет 3 + 0,5 = 3,5 секунды. Если мы выполним тот же код выше с parLapply()
вместо parLapplyLB()
, мы получим то же системное время около 3,5 секунд.
2 ответа:
Для такой задачи, как ваша (и, если уж на то пошло, для любой задачи, для которой мне когда-либо требовалось параллельное)
parLapplyLB
это не совсем подходящий инструмент для работы. Чтобы понять, почему нет, посмотрите, как это реализовано:Проблема заключается в том, что он сначала разбивает свой список заданий на подсписки одинакового размера, которые затем распределяет между узлами, каждый из которых работаетparLapplyLB # function (cl = NULL, X, fun, ...) # { # cl <- defaultCluster(cl) # do.call(c, clusterApplyLB(cl, x = splitList(X, length(cl)), # fun = lapply, fun, ...), quote = TRUE) # } # <bytecode: 0x000000000f20a7e8> # <environment: namespace:parallel> ## Have a look at what `splitList()` does: parallel:::splitList(1:4, 2) # [[1]] # [1] 1 2 # # [[2]] # [1] 3 4
lapply()
на своем заданном подсписке. Итак, ваш первый узел выполняет задания на первом и втором входах, в то время как второй узел запускает задания, используя третий и четвертый входы.Вместо этого используйте более универсальный
clusterApplyLB()
, который работает именно так, как вы надеетесь:system.time( parallel::clusterApplyLB(cl, 1:4, function(y) { if (y == 1) { Sys.sleep(3) } else { Sys.sleep(0.5) }})) # user system elapsed # 0.00 0.00 3.09
parLapplyLB
не балансирует нагрузку, потому что имеет семантическую ошибку. Мы нашли ошибку и предоставили исправление, см. здесь. Теперь, его до разработчиков R, чтобы включить исправление.