допар foreach (параллель для цикла) - PullRequest
0 голосов
/ 10 февраля 2019

Этот вопрос конкретно относится к запуску цикла for на нескольких ядрах.Я пытаюсь научиться запускать код с использованием параллельных ядер.Фактический код несколько сложен, поэтому я воссоздаю очень простой и разбавленный код здесь .Обратите внимание, что этот пример только для иллюстративных целей, а не для реального кода.

library(parallel)
library(foreach)
library(doParallel)

#Creating a mock dataframe
Event_ID = c(1,1,1,1,1,2,2,2,2,2,3,3,3,3)
Type=c("A","B","C","D","E","A","B","C","D","E","A","B","C","D")
Revenue1=c(24,9,51,7,22,15,86,66,0,57,44,93,34,37)
Revenue2=c(16,93,96,44,67,73,12,65,81,22,39,94,41,30)
z = data.frame(Event_ID,Type,Revenue1,Revenue2)
#replicates z 5000 times
n =5000
zz=do.call("rbind", replicate(n, z, simplify = FALSE))
zz$Revenue3 = 0

#################################################################
#   **foreach, dopar failed attempt**
#################################################################
cl=parallel::makeCluster(14,type="PSOCK") #I have 8 core 16 threads but use 14 here. Please edit this accordingly.
registerDoParallel(cl)
home1 = function(zz1){
  foreach(i=1:nrow(zz1), .combine = rbind) %dopar% {
    zz1[i,'Revenue3'] = sqrt(zz1[i,'Revenue1'])+(zz1[i,'Revenue2'])
  }
  return(zz1)
}

zzz = home1(zz1=zz)
stopCluster(cl) 

#################################################################
#Non parallel implementation
#################################################################
home2 = function(zz2){
  zz3=zz2
  for (i in 1:nrow(zz3)){
    zz3[i,'Revenue3'] = sqrt(zz3[i,'Revenue1'])+(zz3[i,'Revenue2'])
  }
  return(zz3)
}
zzzz=home2(zz2=zz)

Я создаю фрейм данных и пытаюсь использовать foreach и dopar, но, похоже, он не работает.Далее я приведу реализацию непараллельной версии кода.Однако, параллельная версия не работает для меня.Выходной df, который я получаю, такой же, как входная матрица.Я понимаю, что могу совершить основную ошибку, но у меня недостаточно опыта, чтобы понять, что именно не так.Буду признателен за любую помощь.

PS Я понимаю, что моя непараллельная версия не является оптимальной и может быть улучшена, но это используется для примера.

1 Ответ

0 голосов
/ 10 февраля 2019

Во-первых, обратите внимание, что параллельная работа с использованием пакета parallel, doParallel или foreach несколько ограничена, когда происходит перезапись значений в существующих data.frames.При выполнении распараллеливания этим пакетом запускается параллельно запущенный сеанс R, рабочий, который выполняет вычисления, возвращая любой результат, который был выполнен в некоторой удобной форме.Это означает, что эти рабочие сеансы не содержат ни одного из объектов в исходном сеансе, если они не предоставлены (с .export или в качестве аргумента функции).Пакеты future, promises и ipc могут допускать асинхронную обработку при изменении переменных в исходном сеансе за счет некоторой простоты.

Обратите внимание, что, поскольку каждый сеанс будет использовать отдельное ядро, используябольше сеансов, чем ядер, в целом снижают производительность.

Что касается самой реализации, то, как вы хотите приблизиться к распараллеливанию, зависит от того, что вам нужно для расчетов и какой формат вы хотите вернуть.Если вы хотите выполнять простые построчные вычисления, вы можете использовать что-то вроде:

library(iterators)
cl=parallel::makeCluster(4) #I have 8 core 16 threads but use 14 here. Please edit this accordingly.
registerDoParallel(cl)
stopCluster(cl)
home1 <- function(zz1){
  output <- foreach(x = iter(zz1, by = "row"), .combine = rbind) %dopar% {
    x[["Revenue3"]] <- sqrt(x[["Revenue1"]]) + x[["Revenue2"]]
    x
  }
  output
}
zzz <- home1(zz1=zz)
stopCluster(cl)

Обратите внимание, что я использовал здесь структуру Iterator, которая может использоваться для эффективной итерации по строкам / столбцам.Если это тот тип вычислений, который вы ищете, я предлагаю использовать векторизованный подход, поскольку это значительно повысит производительность.

zz[["Revenue3"]] <- sqrt(zz[["Revenue2"]) + zz[["Revenue1"]]

Последнее примерно в 13000 раз быстрее на моем крошечном 4-ядерном ноутбуке..

...