Могу ли я установить разную степень параллелизма для разных целей с помощью пакета R {target}?
Я тестирую
targets
package, и у меня возникла проблема с настройкой распараллеливания. Мой рабочий процесс состоит из двух этапов, и я хотел бы распараллелить первый этап для четырех рабочих и второй этап для 16 рабочих.
Я хочу знать, могу ли я решить проблему, позвонив, а затем указав, сколько рабочих процессов требуется на каждом этапе в
tar_target
звонки. У меня есть простой пример ниже, где я бы хотел
data
шаг для выполнения с 1 рабочим, а
sums
шаг для выполнения с 3 рабочими.
library(targets)
tar_dir({
tar_script({
library(future)
library(future.callr)
library(dplyr)
plan(callr)
list(
# Goal: this step should execute with 1 worker
tar_target(
data,
data.frame(
x = seq_len(6),
id = rep(letters[seq_len(3)], each = 2)
) %>%
group_by(id) %>%
tar_group(),
iteration = "group"
),
# Goal: this step should execute with 3 workers, in parallel
tar_target(
sums,
sum(data$x),
pattern = map(data),
iteration = "vector"
)
)
})
tar_make_future()
})
Я знаю, что один из вариантов - настроить параллельный бэкэнд отдельно на каждом шаге, а затем вызвать
tar_make()
для последовательного выполнения рабочего процесса. Мне интересно, смогу ли я получить такой результат с
tar_make_future()
.
2 ответа
Я бы порекомендовал вам позвонить
tar_make_future(workers = <max_parallel_workers>)
и пусть выяснит, сколько рабочих процессов запускать параллельно. автоматически определяет, какие цели могут работать параллельно, а какие нужно дождаться завершения зависимостей восходящего потока. В вашем случае некоторые ветки могут завершиться раньше других, и в этом случае они могут начаться сразу. Другими словами, некоторые ветки начнут работать до того, как смогут запуститься другие ветки, и вы можете доверять
targets
для увеличения временных работников, когда в этом возникает необходимость. Анимация на https://books.ropensci.org/targets/hpc.html#future может помочь визуализировать это. Если бы вы управляли параллелизмом на микроуровне отдельно, вам, вероятно, пришлось бы ждать, пока все
data
закончить до любого из
sum
может начаться, что может занять много времени.
Решение, которое сработало в моем случае, заключалось в том, чтобы позвонить
tar_make_future()
дважды. В приведенном выше примере это будет:
tar_make_future(data, workers = 1)
tar_make_future(workers = 3)
Хотя в моем реальном рабочем процессе это больше похоже на:
tar_make_future(data, workers = 4)
tar_make_future(workers = <max_parallel_workers>)
@landau указывает на то, что это полностью создает цель, прежде чем переходить к следующим шагам. Безусловно, существуют рабочие процессы, в которых чистым и эффективным решением является вызов
tar_make_future(workers = <max_parallel_workers>)
и примите получившуюся среду выполнения.
В моем случае ожидание завершения не было проблемой: мой
data
target содержал много быстрых веток, последующие цели строились намного медленнее, и я мог распараллелить медленный шаг с большим количеством рабочих процессов, чем быстрый шаг (16+ рабочих для медленного шага против всего 4 для быстрого шага). Если это не соответствует вашей ситуации, предложение @landau может быть лучшим решением.