parallel::mclapply() adds or removes bindings to the global environment. Which ones?

。_饼干妹妹 提交于 2019-12-06 09:48:00

You can remove the .Random.seed yourself before you lock the environment. Also you need to load the library (or use the function before) and assign tmp to something.

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

Of course this will not allow functions that need .Random.seed like rnorm to work.

A workaround is to to change the RNG kind to "L'Ecuyer-CMRG", see also here ?nextRNGStream:

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

EDIT

I thought of another solution to your problem and I think this will work with any RNG (did not test much). You can override the function that removes .Random.seed with one that just sets it to 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)

One final thought: you can create a new environment containing all things you don't want to be changed, lock it and work in there.

I think parallel:::mc.set.stream() has the answer. Apparently, mclapply() tries to remove .Random.seed from the global environment by default. Since the default RNG algorithm is Mersenne Twister, we dive into the else block below.

> 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>

We can use mc.set.seed = FALSE to make the following code work, but this is probably not a good idea in practice.

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

I wonder if there is a way to lock the environment while still allowing us to remove .Random.seed.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!