代码之家  ›  专栏  ›  技术社区  ›  landau

parallel::mclappy()添加或删除到全局环境的绑定。哪一个?

  •  2
  • landau  · 技术社区  · 6 年前

    为什么这很重要

    drake ,我希望用户能够执行 mclapply() 在锁定的全局环境中调用。为了再现性,环境被锁定。 Without locking, data analysis pipelines could invalidate themselves

    证据 麦克拉普利() 添加或删除全局绑定

    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年1月16日由 reprex package (v0.2.1)

    编辑

    https://github.com/ropensci/drake/issues/675 https://ropenscilabs.github.io/drake-manual/hpc.html#parallel-computing-within-targets

    2 回复  |  直到 6 年前
        1
  •  4
  •   landau    6 年前

    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)
    

    我想知道是否有一种方法可以锁定环境,同时仍然允许我们删除 .种子 .

        2
  •  3
  •   alko989    6 年前

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

    当然,这将不允许需要 .种子 喜欢 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)
    

    我想到了解决您问题的另一种方法,我认为这将适用于任何RNG(没有进行太多测试)。您可以重写删除的函数 .种子 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)
    

    最后一个想法是:您可以创建一个包含所有不想更改的内容的新环境,将其锁定并在其中工作。

    推荐文章