Как написать эффективные вложенные функции для распараллеливания? - PullRequest
0 голосов
/ 07 марта 2020

У меня есть фрейм данных с двумя группирующими переменными class и group. Для каждого класса у меня есть задание на черчение для группы. В основном у меня есть 2 уровня на class и 500 уровней на group.

Я использую пакет parallel для распараллеливания и mclapply функция для итерации по уровням class и group.

Мне интересно, какой способ записи моих итераций является наилучшим. Я думаю, что у меня есть два варианта:

  1. Запуск распараллеливания для переменной class.
  2. Запуск распараллеливания для переменной group.

Мой компьютер имеет 3 ядра, работающие на R сессию и обычно, сохраняют 4 ядро ​​для моей операционной системы. Мне было интересно, что если выполнить распараллеливание для переменной class с двумя уровнями, 3-е ядро ​​никогда не будет использовано, поэтому я подумал, что будет более эффективно, если все 3 ядра будут работать с распараллеливанием для переменной group. Я написал несколько тестов скорости, чтобы убедиться, что это лучший способ:

library(microbenchmark)
library(parallel)

f = function(class, group, A, B) {

  mclapply(seq(class), mc.cores = A, function(z) {
    mclapply(seq(group), mc.cores = B, function(c) {
      ifelse(class == 1, 'plotA', 'plotB')
    })
  })

}

class = 2
group = 500

microbenchmark(
  up = f(class, group, 3, 1),
  nest = f(class, group, 1, 3),
  times = 50L
)

Unit: milliseconds
 expr       min        lq     mean    median       uq      max neval
   up  6.751193  7.897118 10.89985  9.769894 12.26880 26.87811    50
 nest 16.584382 18.999863 25.54437 22.293591 28.60268 63.49878    50

Результат говорит о том, что я должен использовать распараллеливание для class, а не для переменной group.

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

Условие ifelse используется, потому что предыдущий код, использованный для подготовки данных к задаче построения графика, больше или менее избыточный для обоих уровней class, поэтому я подумал, что было бы более эффективно использовать строковое кодирование и написать более длинную функцию, проверяющую, какой уровень class используется, чем "разбивать" эту функцию на две более короткие функции.

Какие лучше всего писать такой код? Я ясно представляю, но, поскольку я не эксперт в области данных, я хотел бы знать ваш рабочий подход.

Эта угроза связана с этой проблемой. Но я думаю, что мой вопрос касается обеих точек зрения:

  • Код красоты и ясности
  • Скорость исполнения

Спасибо

1 Ответ

0 голосов
/ 13 апреля 2020

Вы спрашивали об этом некоторое время go, но я попытаюсь ответить на тот случай, если кому-то еще будет интересно то же самое. Сначала я хотел бы разделить свою задачу, а затем l oop по каждой части. Это дает мне больше контроля над процессом.

parts <- split(df, c(df$class, df$group))
mclapply(parts, some_function)

Во-вторых, распределение задач по нескольким ядрам требует больших вычислительных затрат и может свести на нет любые выгоды, получаемые вами от распараллеливания вашего сценария. Здесь mclapply разбивает работу на любое количество узлов и выполняет разветвление один раз. Это гораздо эффективнее, чем вложение двух mclapply циклов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...