r %dopar% вложенный цикл не работает параллельно

Я запускаю вложенный цикл с помощью %dopar% создать фиктивный набор данных для целей опыта. Ссылка на ссылку: вложенный 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)

проблема

когда я бегу на %dopar% я контролировал производительность процессора моей машины, используя Resource Monitor и я заметил, что процессоры используются не полностью.

Вопрос

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

1 ответ

Решение

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

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

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

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

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

output <- CJ(ID, year, month)

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

Другие вопросы по тегам