我试图将一个对象(即 R6
类;this particular one)传递给使用 parallel::makePSOCKcluster()
创建的多个工作人员,我得到:
Error in checkForRemoteErrors(val) :
one node produced an error: external pointer is not valid
<块引用>
[...] 有一组对象类型不能传递给另一个 R 进程,并且预期在那里工作。
我想了解我尝试传递的对象是否属于此类别,如果属于,我的选择是什么。
这是一个 MRE:
场景 1: (工作) 在每个 worker 内部创建 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: (不工作) 在 main 中创建 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)
})()
答案 0 :(得分:0)
Roland 指出 environment(model$Solve)
包含一个 private
环境,其中包含一个 externalptr
对象 .work
:
typeof(model$.__enclos_env__$private$.work)
# "externalptr"
这个指针 .work
是使用编译代码创建的,即通过 Rcpp
导出(参见 this export)。
这个指针似乎是由编译代码管理的,因此,我不能在工作人员中使用它。调用编译后的代码并从工作人员内部创建这个指针是可以的。不好的是在另一个进程(即主进程)中创建这个指针,然后将它传递给工作进程。这可能是因为每个 worker 都是作为单独 R
进程创建的,具有自己的内存空间。
不理想,但正如 Roland 指出的那样,可能有效的是以某种方式复制该指针处的数据并确保将其传递给工作人员。但这可能需要 Rcpp
实现。
对于对这个特定包感兴趣的人,您也可以在 GitHub 上关注 this issue。