parallel :: mclapply () добавляет или удаляет привязки к глобальной среде. Какие? - PullRequest
0 голосов
/ 17 января 2019

Почему это важно

Для drake я хочу, чтобы пользователи могли выполнять mclapply() вызовы в заблокированной глобальной среде. Окружающая среда заблокирована ради воспроизводимости. Без блокировок конвейеры анализа данных могут сделать себя недействительными .

Свидетельство того, что mclapply() добавляет или удаляет глобальные привязки

set.seed(0)
a <- 1

# Works as expected.
rnorm(1)
#> [1] 1.262954
tmp <- parallel::mclapply(1:2, identity, mc.cores = 2)

# No new bindings allowed.
lockEnvironment(globalenv())

# With a locked environment
a <- 2 # Existing bindings are not locked.
b <- 2 # As expected, we cannot create new bindings.
#> Error in eval(expr, envir, enclos): cannot add bindings to a locked environment
tmp <- parallel::mclapply(1:2, identity, mc.cores = 2) # Unexpected error.
#> Warning in parallel::mclapply(1:2, identity, mc.cores = 2): all scheduled
#> cores encountered errors in user code

Создано в 2019-01-16 пакетом Представить (v0.2.1)

EDIT

Исходную проблему мотивации см. В https://github.com/ropensci/drake/issues/675 и https://ropenscilabs.github.io/drake-manual/hpc.html#parallel-computing-within-targets.

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Вы можете удалить .Random.seed самостоятельно, прежде чем заблокировать среду. Также вам нужно загрузить библиотеку (или использовать функцию раньше) и присвоить tmp чему-либо.

library(parallel)
tmp <- NULL
rm(".Random.seed", envir = .GlobalEnv, inherits = FALSE)
lockEnvironment(globalenv())
tmp <- parallel::mclapply(1:2, identity, mc.cores = 2)

Конечно, это не позволит функциям, которым требуется .Random.seed, как rnorm, работать.

Обходной путь должен изменить вид RNG на "L'Ecuyer-CMRG", см. Также здесь ?nextRNGStream:

library(parallel)
tmp <- NULL
RNGkind("L'Ecuyer-CMRG")
lockEnvironment(globalenv())
tmp <- parallel::mclapply(1:2, rnorm, mc.cores = 2)

EDIT

Я подумал о другом решении вашей проблемы, и я думаю, что это будет работать с любым RNG (не тестировал много). Вы можете переопределить функцию, которая удаляет .Random.seed, с помощью функции, которая просто устанавливает ее на NULL

library(parallel)
mc.set.stream <- function () {
  if (RNGkind()[1L] == "L'Ecuyer-CMRG") {
    assign(".Random.seed", get("LEcuyer.seed", envir = RNGenv), 
           envir = .GlobalEnv)
  } else {
    if (exists(".Random.seed", envir = .GlobalEnv, inherits = FALSE)) {
      assign(".Random.seed", NULL, envir = .GlobalEnv)
    }  
  }
}

assignInNamespace("mc.set.stream", mc.set.stream, asNamespace("parallel"))
tmp <- NULL
set.seed(0)
lockEnvironment(globalenv())
tmp <- parallel::mclapply(1:2, rnorm, mc.cores = 2)

Одна заключительная мысль: вы можете создать новую среду, содержащую все вещи, которые вы не хотите менять, заблокировать и работать там.

0 голосов
/ 28 января 2019

Я думаю, parallel:::mc.set.stream() имеет ответ. По-видимому, mclapply() пытается удалить .Random.seed из глобальной среды по умолчанию. Так как алгоритм RNG по умолчанию - Mersenne Twister, мы погрузимся в блок else ниже.

> parallel:::mc.set.stream
function () 
{
    if (RNGkind()[1L] == "L'Ecuyer-CMRG") {
        assign(".Random.seed", get("LEcuyer.seed", envir = RNGenv), 
            envir = .GlobalEnv)
    }
    else {
        if (exists(".Random.seed", envir = .GlobalEnv, inherits = FALSE)) 
            rm(".Random.seed", envir = .GlobalEnv, inherits = FALSE)
    }
}
<bytecode: 0x4709808>
<environment: namespace:parallel>

Мы можем использовать mc.set.seed = FALSE, чтобы заставить работать следующий код, но это, вероятно, не очень хорошая идея на практике.

set.seed(0)
lockEnvironment(globalenv())
parallel::mclapply(1:2, identity, mc.cores = 2, mc.set.seed = FALSE)

Интересно, есть ли способ заблокировать среду, позволяя нам удалить .Random.seed.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...