Делит ли parApply () матрицу и затем обрабатывает каждую? - PullRequest
1 голос
/ 26 июня 2019

Предположим, у меня есть вызов parApply() следующим образом:

cl <- makeCluster("FORK", 5)
parApply(cl = cl, X = my.mat, MARGIN = 1, FUN = myFun)

Где nrow(my.mat) очень большой, но myFun() вычисляется очень быстро.Обратите внимание, что количество ядер cl равно 5.Интересно, как осуществляется распараллеливание?

Делится ли my.mat на 5 подматриц, затем каждая обрабатывается потоком, а затем объединяется после завершения всех потоков?Или это делается путем отправки элементов my.mat в каждый поток по одному?

1 Ответ

1 голос
/ 26 июня 2019

Вот некоторые пояснения из документации R:

parLapply , parSapply и parApply - это параллельные версии lapply, Подать и подать заявку. Куски вычислений статически распределяются по узлы, использующие clusterApply . По умолчанию количество чанков одинаково как количество узлов. parLapplyLB , parSapplyLB являются балансировкой нагрузки версии, предназначенные для использования при применении FUN к различным элементам X занимает довольно переменное количество времени, и либо функция детерминированные или воспроизводимые результаты не требуются. Куски вычисления динамически распределяются между узлами с использованием clusterApplyLB .

Обратите внимание, что в R / 3.5.0 внесены некоторые изменения:

Начиная с R 3.5.0, количество чанков по умолчанию равно удвоенному числу узлы. До версии 3.5.0 (фиксированное) количество порций было таким же, как количество узлов. Что касается clusterApplyLB , с балансировкой нагрузки узел, который выполняет определенную работу, является недетерминированным и симуляции, которые назначают потоки ГСЧ узлам, не будут воспроизводиться.

clusterApply вызывает веселье на первом узле с аргументами x [[1]] и ..., на втором узле с x [[2]] и ... и т. д., переработка узлы по мере необходимости.

Существует clauterApplyLB, который работает немного по-другому:

clusterApplyLB является версией балансировки нагрузки clusterApply. Если длина n из х не больше, чем число узлов р, то задание отправлено на n узлов. В противном случае первые p заданий размещаются по порядку на р узлов. Когда первая работа завершается, следующая работа помещается на узел, который стал свободным; это продолжается до тех пор, пока все работы не будут завершены. Использование clusterApplyLB может привести к лучшему использованию кластера, чем используя clusterApply , но увеличение связи может уменьшить спектакль. Кроме того, узел, который выполняет конкретное задание, недетерминирована. Это означает, что симуляции, которые назначают потоки ГСЧ к узлам не будут воспроизводиться.

Поэтому, когда вы используете parApply, ваша матрица делится на 5 блоков. Каждый кусок обрабатывается одним из ядер. В случае семейства функций par * ApplyLB элементы назначаются ядрам одно за другим, и как только ядро ​​завершает свою задачу, ему назначается другое.

Вот вывод следующего кода:

library(parallel)


my.mat <- matrix(c(1:20,rep(0,20)), ncol=2)
head(my.mat)
#      [,1] [,2]
# [1,]    1    0
# [2,]    2    0
# [3,]    3    0
# [4,]    4    0
# [5,]    5    0
# [6,]    6    0

cl <- makeCluster(5, "FORK")
parApply(cl = cl, X = my.mat, MARGIN = 1, FUN = function(x){print(paste("sum= ", sum(x), "  pid=",Sys.getpid()))})
# [1] "sum=  1   pid= 42569" 
# [2] "sum=  2   pid= 42569" 
# [3] "sum=  3   pid= 42569" 
# [4] "sum=  4   pid= 42569" 
# [5] "sum=  5   pid= 42570" 
# [6] "sum=  6   pid= 42570" 
# [7] "sum=  7   pid= 42570" 
# [8] "sum=  8   pid= 42570" 
# [9] "sum=  9   pid= 42571" 
# [10] "sum=  10   pid= 42571"
# [11] "sum=  11   pid= 42571"
# [12] "sum=  12   pid= 42571"
# [13] "sum=  13   pid= 42572"
# [14] "sum=  14   pid= 42572"
# [15] "sum=  15   pid= 42572"
# [16] "sum=  16   pid= 42572"
# [17] "sum=  17   pid= 42573"
# [18] "sum=  18   pid= 42573"
# [19] "sum=  19   pid= 42573"
# [20] "sum=  20   pid= 42573"


stopCluster(cl)

Обратите внимание на разницу со следующим выводом (посмотрите, как распределяются значения pid), если я использую parLapplyLB с размером чанка = 1:

mylist <- 1:20
cl <- makeCluster(5, "FORK")
parLapplyLB(cl = cl, X = mylist,function(x){print(paste("sum= ", sum(x), "  pid=",Sys.getpid()))}, chunk.size = 1)
# [[1]]
# [1] "sum=  1   pid= 64019"
# 
# [[2]]
# [1] "sum=  2   pid= 64020"
# 
# [[3]]
# [1] "sum=  3   pid= 64021"
# 
# [[4]]
# [1] "sum=  4   pid= 64022"
# 
# [[5]]
# [1] "sum=  5   pid= 64023"
# 
# [[6]]
# [1] "sum=  6   pid= 64019"
# 
# [[7]]
# [1] "sum=  7   pid= 64020"
# 
# [[8]]
# [1] "sum=  8   pid= 64019"
# 
# [[9]]
# [1] "sum=  9   pid= 64020"
# 
# [[10]]
# [1] "sum=  10   pid= 64019"
# . . .
stopCluster(cl)
...