2016-09-13 2 views
2

Я использую этот код:Когда (если когда-либо) я должен сказать R параллельно, чтобы не использовать все ядра?

library(parallel) 
cl <- makeCluster(detectCores() - 1) 
clusterCall(cl, function(){library(imager)}) 

то у меня есть функция упаковщик ищет что-то вроде этого:

d <- matrix #Loading a batch of data into a matrix 
res <- parApply(cl, d, 1, FUN, ...) 
# Upload `res` somewhere 

я тестировал на моем ноутбуке, с 8 ядрами (4 ядра, гиперпотоковой) , Когда я запустил его на 50 000 строк, 800 столбцов, матрицу, потребовалось 177,5 с, и большую часть времени 7 ядер поддерживали почти на 100% (по словам сверху), то он сидел там в течение последних 15 или так секунд, что, я думаю, сочетало результаты. Согласно system.time(), пользовательское время составляло 14 секунд, чтобы совпадало.

Теперь я работаю на EC2, 36-ядерный c4.8xlarge, и я вижу, что он проводит почти все свое время только с одним ядром на 100%. Точнее: происходит примерно 10-20 секунд, когда используются все ядра, то около 90 секунд всего одного ядра на 100% (используется R), затем около 45 секунд другого материала (где я сохраняю результаты и загрузите следующую партию данных). Я делаю партии из 40 000 строк, 800 столбцов.

Долгосрочная средняя нагрузка, согласно сверху, колеблется около 5,00.

Это кажется разумным? Или существует точка, в которой R-параллелизм тратит больше времени на коммуникационные издержки, и я должен ограничивать, например, 16 ядер. Здесь есть какие-либо эмпирические правила?

Ссылка: CPU spec Я использую «Linux 4.4.5-15.26.amzn1.x86_64 (amd64)». R 3.2.2 (2015-08-14)

ОБНОВЛЕНИЕ: Я пробовал с 16 ядрами. Для наименьших данных время выполнения увеличилось с 13,9 до 18,3 с. Для средних данных:

With 16 cores: 
    user system elapsed 
30.424 0.580 60.034 

With 35 cores: 
    user system elapsed 
30.220 0.604 54.395 

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

Я также пробовал использовать mclapply(), как это предлагается в комментариях. Казалось, что это немного быстрее (примерно 330 против 360-х годов по конкретным тестовым данным, которые я пробовал), но это было на моем ноутбуке, где другие процессы или перегрев могут повлиять на результаты. Итак, я пока не делаю никаких выводов.

+0

Это зависит от конкретной используемой функции и от того, сколько данных необходимо скопировать для каждой задачи. Как правило, накладные расходы на параллелизацию не должны сильно зависеть от количества ядер. – Roland

+0

@Roland. Это зависит, по крайней мере, линейно от количества ядер, а в более сложных схемах параллелизации зависимость может быть даже суперлинейной IIRC. –

+1

@KonradRudolph Спасибо. Однако обычно это должно быть компенсировано временем, сохраненным за счет использования большего количества ядер (по крайней мере, при сравнении от 16 до 36 ядер). Если это не так, OP, вероятно, копирует большие объекты в рабочие и из рабочих. – Roland

ответ

2

Нет полезных правил большого пальца - количество ядер, для которых оптимальная параллельная задача полностью определяется указанной задачей. Для более общей дискуссии см. Gustafson’s law.

Высокая одноядерная часть, которую вы видите в своем коде, вероятно, исходит из конечной фазы алгоритма (фаза «присоединиться»), где параллельные результаты объединены в единую структуру данных. Поскольку это намного превосходит параллельную фазу вычисления, это действительно может быть признаком того, что меньшее количество ядер может быть полезным.

+0

Ну, это также зависит от * других * задач - что еще работает на этом компьютере ;-) –

2

Я бы добавил, что если вы не знаете об этом замечательном ресурсе для параллельных вычислений в R, вы можете прочитать недавнюю книгу Нормана Матлоффа Parallel Computing for Data Science: With Examples in R, C++ and CUDA очень полезное чтение. Я бы очень рекомендовал его (я многому научился, не из CS-фона).

В книге подробно рассматривается ваш вопрос (глава 2). В книге дается краткий обзор причин накладных расходов, которые приводят к узким местам для параллельных программ.

раздел 2.1, который неявно частично отвечает на ваш вопрос Цитирование:

Существуют две основные проблемы производительности в параллельном программировании:

Связь накладных расходов: Как правило, данные должны быть перенесены назад и вперед между процессы. Это требует времени, которое может принести довольно большой результат . Кроме того, процессы могут попасть друг другу в , если все они попытаются получить доступ к тем же данным одновременно. Они могут столкнуться, когда пытается получить доступ к одному каналу связи, к тому же модулю памяти и т. Д. Это еще один сок на скорости. Термин гранулярность используется, чтобы относиться, грубо говоря, к соотношению вычислений к накладным расходам. Крупнозернистые или крупнозернистые алгоритмы включают в себя достаточно большие куски вычислений, что накладные расходы не являются большой проблемой. В мелкозернистых алгоритмах нам действительно нужно избегать накладных расходов, насколько возможно .

^Когда накладные расходы высоки, меньшее количество сердечников для данной проблемы может дать более короткое общее время вычислений.

Балансировка нагрузки: Как отмечалось в предыдущей главе, если мы не осторожны в том, каким образом отнесем работу к процессам, мы рискуем назначая гораздо больше работы, чем к некоторым другим. Это компрометирует работу , так как она оставляет некоторые процессы непродуктивными в конце прогонов, в то время как еще предстоит выполнить работу.

Если, если вообще не использовать все сердечники? Один из примеров из моего личного опыта работы с ежедневными cronjobs в R по данным, которые составляют 100-200 ГБ данных в ОЗУ, в которых запущены несколько ядер для разбиения блоков данных, я действительно нашел работу с указанием 6 из 32 доступных ядер быть быстрее, чем использовать 20-30 ядер. Основной причиной были требования к памяти для дочерних процессов (после того, как определенное количество дочерних процессов было в действии, использование памяти стало высоким, и ситуация значительно замедлилась).