параллельное суммирование матриц (или растров) в R

У меня есть длинный список больших матриц (или растров), которые я хочу суммировать параллельно. На выходе должна быть матрица. Я пробовал foreach использовать .combine='+' функцию, которая работает, но кажется, что .combine работает только в одном потоке, поэтому нет ускорения. Какие-либо предложения? Спасибо

matrix.list <- list()
for(i in 1:10000) matrix.list[[i]] <- matrix(1,nrow=100,ncol=100)

library(foreach)
library(doMC)
registerDoMC(cores=2)

matrix.sum <- foreach(i=1:10000,.combine='+') %dopar% matrix.list[[i]]

person Eric Collins    schedule 07.09.2016    source источник
comment
точно. У меня 600000 матриц размером 7200х3600   -  person Eric Collins    schedule 07.09.2016
comment
они редкие, но я не хотел все усложнять   -  person Eric Collins    schedule 07.09.2016
comment
Не параллельное решение, но Reduce('+', matrix.list) работало примерно в 18 раз быстрее, чем приведенный выше код.   -  person jav    schedule 07.09.2016
comment
Конечно, он работает только на одном ядре. Он запускается после параллельной петли. Все, что вы делаете там параллельно, - это извлечение списка. Если вы хотите использовать распараллеливание, добавление матриц следует выполнять по частям.   -  person Roland    schedule 07.09.2016


Ответы (1)


Ваша проблема в том, что вы выполняете только matrix.list[[i]] параллельно, а [[ очень быстро для списков. Операция .combine выполняется главным процессом после завершения всех параллельных задач.

Вы должны разделить свой список на такие части:

set.seed(42)
n <- 1e3
matrix.list <- replicate(n, matrix(rnorm(1),nrow=1000,ncol=1000), simplify = FALSE)

system.time({
matrix.sum_s <- Reduce("+", matrix.list)
})
#user  system elapsed 
#1.83    1.25    3.08

library(foreach)
library(doParallel)
ncl <- 4
cl <- makeCluster(ncl)
registerDoParallel(cl)

system.time({
matrix.sum_p <- foreach(x = split(matrix.list, (seq_len(n) - 1) %/% (n/ncl)), 
                       .combine='+') %dopar% 
   {Reduce("+", x)}
})
#user  system elapsed 
#6.49   35.97   46.97 
stopCluster(cl)

all.equal(matrix.sum_s, matrix.sum_p)
#[1] TRUE

Конечно, распараллеленная версия все еще намного медленнее, чем просто использование Reduce. Почему? Потому что + - это быстрая низкоуровневая (.Primitive) функция. foreach тратит время в основном на копирование нескольких ГБ плотных матриц.

person Roland    schedule 07.09.2016