Параллельная обработка в R сделана неправильно?

У меня есть код, который я пытаюсь обработать параллельно с помощью пакета foreach. Код работает, но когда я запускаю его на компьютере с 4 ядрами, это занимает около 26 минут, а когда я переключаюсь на компьютер с 32 ядрами, для завершения по-прежнему требуется 13 минут. Мне было интересно, делаю ли я что-то не так, поскольку я использую в 8 раз больше ядер, но сокращаю время только вдвое. Мой код выглядит так:

no_cores <- detectCores()
cl <- makeCluster(no_cores)
registerDoParallel(cl)
Xenopus_Data <- foreach(b=1:length(newly_populated_vec),.packages = c("raster", "gdistance", "rgdal","sp")) %dopar% { Xenopus_Walk(altdata=altdata,water=water,habitat_suitability=habitat_suitability,max_range_without_water=max_range_without_water,max_range=max_range,slope=slope,Start_Pt=newly_populated_vec[b]) }
stopCluster(cl)  

Для компьютера с 4 ядрами я получаю следующее время:

Time_of_Start
[1] "2016-07-12 13:07:23 CEST"
Time_of_end
[1] "2016-07-12 13:33:10 CEST"

And for the one with 32 cores:
Time_of_Start
[1] "2016-07-12 14:35:48 CEST"
Time_of_end
[1] "2016-07-12 14:48:08 CEST"

Это нормально ? и если да, то кто-нибудь знает, как его дополнительно ускорить, может, с помощью других пакетов? Любая помощь приветствуется!

РЕДАКТИРОВАТЬ: это время, которое я получаю после внесения исправлений, как было предложено. Для 32 ядер:

User      System     elapsed 
5.99       40.78      243.97

Для 4 ядер:

user  system  elapsed 
  1.91    0.94  991.71 

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


person snoops    schedule 12.07.2016    source источник
comment
трудно сказать, разумно ли время, не зная размера данных по сравнению со сложностью расчета.   -  person agenis    schedule 12.07.2016
comment
Спасибо за ответ. Да, я подумал, что это может быть проблемой для любого, кто пытается ответить на этот вопрос, но расчет основан на довольно сложной функции, которую я написал сам, поэтому я не думаю, что кто-то действительно будет работать с ней, если я опубликую ее. В любом случае данных тоже достаточно много, так как функция требует несколько растровых слоев. Есть ли у вас какой-либо опыт относительно моего последнего вопроса (есть ли пакеты быстрее, чем foreach, и является ли foreach вообще хорошим пакетом для параллельной обработки)? Я довольно новичок в этом вопросе...   -  person snoops    schedule 12.07.2016
comment
Во-первых, попробуйте проверить количество зарегистрированных ядер на getDoParWorkers(), чтобы убедиться, что с этим все в порядке. (до foreach)   -  person 989    schedule 12.07.2016
comment
@ m0h3n, спасибо за подсказку. Хотя число, возвращаемое getDoParWorkers(), равно количеству ядер, имеющихся в моем распоряжении, это полезная функция, которую я буду использовать, чтобы проверить, все ли в порядке. еще не знал об этом.   -  person snoops    schedule 12.07.2016


Ответы (1)


Попробуйте это и дайте мне знать, если ваша проблема решена:

library(doParallel)
library(foreach)
registerDoParallel(cores=detectCores())
n <- length(newly_populated_vec)
cat("\nN = ", n, " | Parallel workers count = ", getDoParWorkers(), "\n\n", sep="")

t0 <- proc.time()
Xenopus_Data <- foreach(b=1:n,.packages = c("raster", "gdistance", "rgdal","sp"), .combine=rbind) %dopar% { 
        Xenopus_Walk(
        water=water,
        altdata=altdata,
        habitat_suitability=habitat_suitability,
        max_range_without_water=max_range_without_water,
        max_range=max_range,
        slope=slope,
        Start_Pt=newly_populated_vec[b]) 
}
TIME <- proc.time() - t0

Кроме того, попробуйте отслеживать логические ядра на вашем ПК/ноутбуке, чтобы проверить, все ли ядра задействованы в вычислениях. (Диспетчер задач для Windows и htop для Linux)

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

person 989    schedule 12.07.2016
comment
Это сработало, спасибо. Можете ли вы сказать мне, в чем разница между нашими двумя подходами, чтобы я мог понять, почему ваш работает лучше? Я отредактирую новое время в своем вопросе выше. - person snoops; 12.07.2016
comment
@snoops, использующий registerDoParallel(), заботится как о регистрации, так и об остановке кластеров. Также .combine=rbind используется для объединения результатов параллельных потоков. Более того, с таким таймингом прямо перед циклом foreach и после него вы можете более точно определить время, которое занимает ваша параллельная работа. - person 989; 12.07.2016