2015-07-26 2 views
1

Я пытаюсь раздобыть свою библиотеку и использовать ее в библиотеке Snowfall.R Проблемы с снегопадом

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

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

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()), кажется, работает. Но мне кажется, что это более или менее обходное решение, а не очень похожее на снегопад решение.

ответ

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 «d до запуска кластера и используется sfExport для экспорта foo.bar для каждого узла.

+0

Отлично, это именно то, что я искал! Кроме того, если мне нужно загрузить (через функцию get) или записать (назначить) переменную внутри функции, которая объявлена ​​в другом скрипте, но вызвана с другой функцией (... я знаю .. :)), я иногда получил ошибку, что среда не найдена. Мое решение состояло в том, чтобы поиграть с функцией parent.frame(), т.е.включая n = 2, 3, 4 в зависимости от вложенных функций! – David

+0

Какая разница между снегопадом и doSnow? – skan

Смежные вопросы