R Проблемы среды снегопада

Я пытаюсь разобраться в библиотеке Snowfall и ее использовании.

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

Чтобы прояснить ситуацию, давайте рассмотрим следующие два сценария:

q_func.R объявляет функцию

foo.bar <- function(x, envname) assign("val", x, envir = get(envname))
# assigns the value x to the variable "val" in the environment envname

q_snowfall.R основная функция, использующая снегопад.

library(snowfall)
SnowFunc <- function(envname) {
    # load the functions

    # Option 1 not working
    source("q_func.R")
    # Option 2 working...
    # foo.bar <- function(x, envname) assign("val", x, envir = get(envname))


    # create the new environment
    assign(envname, new.env())

    # use the function as declared in q_func.R 
    # to assign random numbers to the new env
    foo.bar(x = rnorm(1), envname = envname)

    # return the environment including the random values
    return(get("val", envir = get(envname)))
}

sfInit(parallel = TRUE, cpus = 2)
# create environment 'a' and 'b' that each will get a new variable 
# called 'val' that gets assigned a random value

envs <- c("a", "b")
result <- sfClusterApplyLB(envs, SnowFunc)
sfStop()

Если я выполню скрипт "q_snowfall.R", я получу ошибку

Error in checkForRemoteErrors(val) : 
  2 nodes produced errors; first error: object 'a' not found

Однако, если я использую второй вариант (объявление функции в функции SnowFunc, ошибка исчезает.

Вы знаете, как Snowfall справляется с различными средами? Или у вас есть решение проблемы. (обратите внимание, что 'q_func.R' на самом деле занимает около 100 строк кода, поэтому я бы предпочел хранить его в отдельном файле, поэтому вариант «сохранить 2» не является решением!)

Большое спасибо!

Изменить. Если я изменю все get(envname) на get(envname, envir = globalenv()), похоже, это сработает. Но мне кажется, что это более или менее обходной путь, а не очень похожее на снегопад решение.


person David    schedule 26.07.2015    source источник


Ответы (1)


Я думаю, проблема не в snowfall, а в том, что вы передаете среду по имени (как символу). Вам не нужно изменять все вхождения get, и смотреть в globalEnv действительно может быть небезопасно.

Достаточно изменить вызов get в foo.bar, чтобы вместо этого искать parent.frame() (т. Е. Среду, из которой был вызван foo.bar). На моей машине работало следующее.

новый q_func.R

foo.bar <- function(x, envname) assign("val", x, envir=get(envname,
                                pos=parent.frame()))

(не так) новый q_snowfall.R

library(snowfall)
SnowFunc <- function(envname) {

    assign(envname, new.env())
    foo.bar(x = rnorm(1), envname = envname)

    return(get("val", envir = get(envname)))
}

source("q_func.R")
sfInit(parallel = TRUE, cpus = 2)
sfExport("foo.bar")

envs <- c("a", "b")
result <- sfClusterApplyLB(envs, SnowFunc)
sfStop()

Также обратите внимание, что я source использовал перед запуском кластера и использовал sfExport для экспорта foo.bar на каждый узел.

person SimonG    schedule 26.07.2015
comment
Отлично, это было именно то, что я искал! Кроме того, если мне нужно загрузить (с помощью функции get) или записать (назначить) переменную в функции, которая объявлена ​​в другом сценарии, но вызывается с помощью другой функции (... я знаю ... :)), я иногда получал ошибка, что среда не найдена. Мое решение состояло в том, чтобы поиграть с функцией parent.frame (), т.е. включая n = 2, 3, 4 в зависимости от вложенных функций! - person David; 27.07.2015
comment
В чем разница между снегопадом и doSnow? - person skan; 17.06.2016