Прежде чем выполнять какое-либо действие параллельно, следует попытаться выяснить, возможна ли какая-либо векторизация. И как только это будет сделано, вопрос «разумна ли параллелизация?»
В этом конкретном примере распараллеливание вряд ли будет таким быстрым, как вы ожидаете, так как на каждой итерации вы сохраняете свои выходные данные в общий объект. R обычно не поддерживает это в распараллеливании, и вместо этого нужно искать распараллеливание в так называемых «смущающе параллельных» задачах, пока не получат лучшее понимание того, как работают параллельные проблемы. Вкратце: не выполняйте параллельные изменения данных в R, если вы не знаете, что делаете. Это вряд ли будет быстрее.
Тем не менее, в вашем случае это становится довольно сложно. Похоже, вы выполняете «Rolling-Max Window», и вывод должен быть сохранен в комбинированной матрице. Альтернативный способ сохранения данных непосредственно в матрице - это вернуть матрицу с 3 столбцами x
, i
, j
, где два последних являются индексами, которые указывают, какой строке / столбцу соответствует значение x
должны быть помещены в.
Чтобы это работало, как отметил Дмитрий в своем ответе, данные необходимо экспортировать в каждый cluster
(параллельный сеанс), чтобы мы могли его использовать. После этого в следующем примере показано, как можно выполнить парализацию
Сначала: создайте кластер и экспортируйте набор данных
set.seed(1)
#Generate test example
n <- 3000
dat <- matrix(runif(n^2), ncol = n)
library(foreach)
library(doParallel)
#Create cluster
cl <- parallel::makeCluster(parallel::detectCores())
#Register it for the foreach loop
doParallel::registerDoParallel(cl)
#Export the dataset (could be done directly in the foreach, but this is more explicit)
parallel::clusterExport(cl, "dat")
Далее мы подходим к циклу foreach
. Обратите внимание, что согласно документации, вложенные циклы foreach
должны быть разделены с помощью тега %:%
, как показано в моем примере ниже:
output <- foreach(i = 1:(nrow(dat)/30), .combine = rbind, .inorder = FALSE) %:%
foreach(j = 1:(ncol(dat)/30), .combine = rbind, .inorder = FALSE) %dopar%{
row <- 30 * (i - 1) + 1
col <- 30 * (j - 1) + 1
c(x = max(dat[row:(row + 29), col:(col + 29)]), i = i, j = j)
}
Примечание .inorder = FALSE
. Когда я возвращаю индексы, меня не волнует порядок, только скорость.
И последнее, но не менее важное: нам нужно создать матрицу. Пакетная функция Matrix
Matrix::SparseMatrix
позволяет задавать значения и индексы.
output <- Matrix::sparseMatrix(output[,"i"], output[,"j"], x = output[,"x"])
Это все еще довольно медленно. Для n = 3000
для выполнения вычислений потребовалось примерно 6 секунд + немаловажные накладные расходы на экспорт данных. Но это, вероятно, быстрее, чем тот же метод с использованием последовательных циклов.