0

我试图将一个对象(即R6类;这个特定的对象)传递给使用创建的许多工作人员parallel::makePSOCKcluster(),我得到:

Error in checkForRemoteErrors(val) : 
  one node produced an error: external pointer is not valid

基于Henrik Bengtsson这篇文章

[...] 有一组对象类型不能被传递到另一个 R 进程并且可以在那里工作。

我想了解我试图传递的对象是否属于这一类,如果是,我的选择是什么。

这是一个MRE:

场景1:( 工作)model在每个工人内部创建对象。

(function() {
    # Create cluster.
    cluster <- parallel::makePSOCKcluster(parallel::detectCores() - 1)

    # Stop cluster.
    on.exit(parallel::stopCluster(cluster))

    # Bare minimum data.
    x <- matrix(rnorm(100), 10, 10)
    y <- runif(10)

    # Run operation.
    result <- parallel::parSapply(cluster, c(1), function(i) {
        # The 'osqp' object.
        model <- osqp::osqp(P = crossprod(x), q = -crossprod(x, y), pars = list(verbose = FALSE))

        # Calling the solver.
        return(model$Solve()$x)
    })

    # Inspect result.
    print(result)
})()

场景 2:( 不工作)主要创建model对象并将其传递给工作人员。

(function() {
    # Create cluster.
    cluster <- parallel::makePSOCKcluster(parallel::detectCores() - 1)

    # Stop cluster.
    on.exit(parallel::stopCluster(cluster))

    # Bare minimum data.
    x <- matrix(rnorm(100), 10, 10)
    y <- runif(10)

    # The 'osqp' object.
    model <- osqp::osqp(P = crossprod(x), q = -crossprod(x, y), pars = list(verbose = FALSE))

    # Run operation.
    result <- parallel::parSapply(cluster, c(1), function(i) {
        # Calling the solver.
        return(model$Solve()$x)
    })

    # Inspect result.
    print(result)
})()

方案 1有效,所以我似乎可以osqp在工人内部使用。但是,当我在外部创建该对象并将其传递给工作人员(即场景 2)时,它失败了。

为了提供更多的上下文,我无法控制model创建。我收到一个在别处创建的实例,我只被允许在该实例上调用几个方法(例如,$Update())。


更新 1

这似乎与R6实例是环境这一事实无关。以下仍然按预期工作。

# Create mock model class.
ModelMock <- R6::R6Class("ModelMock",
    public = list(
        Solve = function() {
            return(list(x = "Mocked model output."))
        }
    )
)

(function() {
    # Create cluster.
    cluster <- parallel::makePSOCKcluster(parallel::detectCores() - 1)

    # Stop cluster.
    on.exit(parallel::stopCluster(cluster))

    # The mocked 'osqp' object.
    model <- ModelMock$new()

    # Run operation.
    result <- parallel::parSapply(cluster, c(1), function(i) {
        # Calling the solver.
        return(model$Solve()$x)
    })

    # Inspect result.
    print(result)
})()
4

1 回答 1

0

Roland指出,environment(model$Solve)包含一个包含对象的private环境:externalptr.work

typeof(model$.__enclos_env__$private$.work)  ​
# "externalptr"

该指针.work是使用编译后的代码创建的,即通​​过Rcpp导出(请参阅此导出)。

似乎这个指针是由编译代码管理的,因此,我不能在工作人员中使用它。调用编译后的代码并从工作人员中创建这个指针是很好的。不好的是在另一个进程(即主进程)中创建这个指针,然后将它传递给工作进程。这可能是因为每个工作人员都是作为一个单独 R的进程创建的,具有自己的内存空间。

并不理想,但正如Roland指出的那样,可行的方法是以某种方式复制该指针处的数据并确保将其传递给工作人员。但这可能需要Rcpp实施。

对于那些对这个特定包感兴趣的人,你也可以在 GitHub 上关注这个问题。

于 2021-06-23T10:08:55.943 回答