Могу ли я установить разную степень параллелизма для разных целей с помощью пакета R {target}?

Я тестирую targetspackage, и у меня возникла проблема с настройкой распараллеливания. Мой рабочий процесс состоит из двух этапов, и я хотел бы распараллелить первый этап для четырех рабочих и второй этап для 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>) и примите получившуюся среду выполнения.

В моем случае ожидание завершения не было проблемой: мой datatarget содержал много быстрых веток, последующие цели строились намного медленнее, и я мог распараллелить медленный шаг с большим количеством рабочих процессов, чем быстрый шаг (16+ рабочих для медленного шага против всего 4 для быстрого шага). Если это не соответствует вашей ситуации, предложение @landau может быть лучшим решением.

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