Распараллеленный сетчатый вызов с ошибкой foreach

#python #r #foreach #parallel-processing #reticulate

Вопрос:

Привет, я пытаюсь вызвать функцию python с помощью reticulate параллельным образом, используя foreach примерно так:

 library(reticulate)
library(doParallel)
library(foreach)
library(parallel)

py_install("wandb")
wandb <- import("wandb")


cl <- makeCluster(detectCores(), type = 'PSOCK')
registerDoParallel(cl)
foreach(i = 1:5) %dopar% {
    wandb$init(project = "test")
}
 

дает:

 Error in {: task 1 failed - "attempt to apply non-function"
Traceback:

1. foreach(i = 1:5) %dopar% {
 .     wandb$init(project = "test")
 . }
2. e$fun(obj, substitute(ex), parent.frame(), e$data)
 

foreach Пакет не работает с reticulate?

Комментарии:

1. Что это за объект wandb ? Я думаю wandb$init(project = "test") , что это не работает, поскольку это каким-то образом смешивает оператор на основе данных $ с функцией ( ... ) . Возможно, вы хотели что-то вроде wandb$init[project == "test"] (что, скорее всего, тоже не сработает… возможно wandb$init[wandb$project == "test"] ).

2. wandb — это библиотека python, импортированная через reticulate.

3. Использует ли он этот специальный синтаксис? Потому R что я ожидал бы некоторых незначительных синтаксических изменений.

4. Это никак не сработает, reticulate не поддерживает многопоточность, потому что весь сеанс python встроен в родительский сеанс R. Если вы хотите сделать это параллельно, импортируйте функцию из каждого дочернего процесса R.

Ответ №1:

Вы не можете экспортировать сетчатые python.builtin.module объекты из одного процесса R в другой. Они предназначены для работы только в рамках того же процесса R, который они создали. Если вы попытаетесь, то получите сообщение об ошибке, о котором сообщаете.

Если вы используете future framework для своего распараллеливания, вы можете проверить это и немедленно выдать информативное сообщение об ошибке, например

 library(reticulate)
library(foreach)
library(doFuture)
registerDoFuture()
cl <- parallelly::makeClusterPSOCK(2L)
plan(cluster, workers = cl)

## Detect non-exportable objects and give an error asap
options(future.globals.onReference = "error")

# py_install("wandb")
wandb <- import("wandb")

res <- foreach(i = 1:5) %dopar% {
  wandb$init(project = "test")
  sqrt(i)
}
 

Вызов foreach() приведет к:

 Error: Detected a non-exportable reference ('externalptr') in one of
the globals ('wandb' of class 'python.builtin.module') used in the
future expression
 

Подробнее об этом можно прочитать в https://future.futureverse.org/articles/future-4-non-exportable-objects.html#package-reticulate .

Обходным путем было бы создание wandb объекта в каждой итерации, которая выполняется на рабочем конце. Что-то вроде:

 res <- foreach(i = 1:5) %dopar% {
  wandb <- import("wandb")
  wandb$init(project = "test", mode = "offline")
  sqrt(i)
}
 

Отказ от ответственности: Я ничего не знаю о модуле Python ‘wandb’. Возможно, вышесказанное не имеет смысла.

Комментарии:

1. спасибо @HenrikB за объяснение и обходной путь.