r% dopar% вложенный цикл не работает параллельно - PullRequest
0 голосов
/ 19 февраля 2019

Я запускаю вложенный цикл, используя %dopar% для генерации фиктивного набора данных для целей опыта. Ссылка на ссылку: R вложенный foreach% dopar% во внешнем цикле и% do% во внутреннем цикле

образец набора данных

set.seed(123)
n = 10000 #number of unique IDs (10k as trial) , real data consits of 50k unique IDs
ID <- paste(LETTERS[1:8],sample(n),sep = "")
year <- c('2015','2016','2017','2018')
month <- c('1','2','3','4','5','6','7','8','9','10','11','12')

предварительноопределенная библиотека

library(foreach)  
library(data.table)
library(doParallel)

# parallel processing setting
cl <- makeCluster(detectCores() - 1)
registerDoParallel(cl)

Тест 1: сценарий% dopar%

system.time(
  output_table <- foreach(i = seq_along(ID), .combine=rbind, .packages="data.table") %:%
    foreach(j = seq_along(year), .combine=rbind, .packages="data.table") %:%
    foreach(k = seq_along(month), .combine=rbind, .packages="data.table") %dopar% {

    data.table::data.table(
      mbr_code = ID[i],
      year = year[j],
      month = month[k]
    )
  }
)
stopCluster(cl)

#---------#
# runtime #
#---------#
>    user  system elapsed 
> 1043.31   66.83 1171.08

Тест 2: сценарий% do%

system.time(
  output_table <- foreach(i = seq_along(ID), .combine=rbind, .packages="data.table") %:%
    foreach(j = seq_along(year), .combine=rbind, .packages="data.table") %:%
    foreach(k = seq_along(month), .combine=rbind, .packages="data.table") %do% {

    data.table::data.table(
      mbr_code = ID[i],
      year = year[j],
      month = month[k]
    )
  }
)
stopCluster(cl)

#---------#
# runtime #
#---------#
> user  system elapsed 
> 1101.85    1.02 1110.55 

Ожидаемые результаты вывода

> view(output_table)

enter image description here

Проблема

при работе на %dopar% я контролировал производительность процессора моей машины с помощью Resource Monitor и заметил процессорыне используются полностьюenter image description here

Вопрос

Я пытался запустить вышеуказанный скрипт (test1 и test2) на моей машине i5, 4 ядра.Но кажется, что время выполнения для %do% и %dopar% близко друг к другу.Это проблема с моим сценарием?Мои реальные данные состоят из 50k уникальных идентификаторов. Это означает, что при работе в %do% потребуется очень много времени. Как я могу полностью использовать ЦП моей машины, чтобы сократить время работы?

1 Ответ

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

Я полагаю, что вы видите начальные издержки пакета foreach, поскольку он копирует и настраивает все необходимое для правильной работы каждого из циклов.После выполнения вашего кода в течение 30 - 60 секунд все мои процессоры слишком сильно загружались, пока код не был окончательно выполнен.

Тем не менее, это не объясняет, почему ваш код такой медленный по сравнению с циклами %do%.Я полагаю, что грешник здесь в том, как применяется цикл foreach, когда вы пытаетесь получить доступ к данным через все циклы foreach.По сути, если вы не экспортируете нужные данные, он попытается получить доступ к одним и тем же данным в нескольких параллельных сеансах, и каждому сеансу придется ждать, пока другие сеансы завершат доступ к своим собственным данным.Вероятно, это можно облегчить, экспортировав данные с помощью аргумента .export в foreach.Лично я использую другой пакет для выполнения большей части моих парализаций, поэтому я предлагаю проверить это, если вы этого хотите.Однако это привело бы к большим издержкам.

Более быстрые методы:

Теперь, когда вы пытаетесь создать фиктивный набор данных, для которого объединяются все комбинации определенных столбцов, существуют более быстрые методы.получения этого.Быстрый поиск по кросс-объединению приведет вас к таким сообщениям.

Для пакета data.table это можно сделать чрезвычайно эффективно и быстрее, используя функцию 'CJ',Просто

output <- CJ(ID, year, month)

даст результат, который пытаются создать вложенные циклы, используя всего около 0,07 секунды для выполнения задачи.

...