我尝试设置并行任务,每个工作人员都需要进行数据库查询。我尝试使用this question中的连接设置每个工作人员,但每次尝试时都会返回<Expired PostgreSQLConnection:(2781,0)>
,因为我注册的工作人员很多。
这是我的代码:
cl <- makeCluster(detectCores())
registerDoParallel(cl)
clusterEvalQ(cl, {
library(RPostgreSQL)
drv<-dbDriver("PostgreSQL")
con<-dbConnect(drv, user="user", password="password", dbname="ISO",host="localhost")
})
如果我尝试运行我的foreach
尽管有错误,则会因task 1 failed - "expired PostgreSQLConnection"
当我进入postgres服务器状态时,它会显示已创建的所有活动会话。
我从主R实例中与postgres交互时没有任何问题。
如果我跑
clusterEvalQ(cl, {
library(RPostgreSQL)
drv<-dbDriver("PostgreSQL")
con<-dbConnect(drv, user="user", password="password", dbname="ISO",host="localhost")
dbGetQuery(con, "select inet_client_port()")
})
然后它将返回所有客户端端口。它没有给我过期的通知但是如果我尝试运行我的foreach命令它将失败并出现相同的错误。
编辑:
我在Ubuntu和2台Windows电脑上试过这个,它们都给出了同样的错误。
另一个编辑:
现在有3台Windows电脑
答案 0 :(得分:5)
我能够在本地重现您的问题。我不完全确定,但我认为问题与clusterEvalQ
内部工作方式有关。例如,你说dbGetQuery(con, "select inet_client_port())
给你客户端端口输出。如果在群集节点上实际评估/执行了查询,那么您将无法看到此输出(与您无法直接读取在外部群集节点上执行的任何其他输出或打印语句的方式相同)。
因此,我的理解是,评估以某种方式首先在本地环境中执行,相关的函数和变量随后被复制/导出到各个clusternode。这适用于任何其他类型的函数/变量,但显然不适用于数据库连接。如果连接/端口映射链接到主R实例,则连接将无法从从属实例起作用。如果您尝试使用clusterExport
函数来导出在主实例上创建的连接,您也会得到完全相同的错误。
作为替代方案,您可以做的是在单个foreach
任务中创建单独的连接。我已经使用本地数据库验证了以下工作:
library(doParallel)
nrCores = detectCores()
cl <- makeCluster(nrCores)
registerDoParallel(cl)
clusterEvalQ(cl,library(RPostgreSQL))
clusterEvalQ(cl,library(DBI))
result <- foreach(i=1:nrCores) %dopar%
{
drv <- dbDriver("PostgreSQL")
con <- dbConnect(drv, user="user", password="password", dbname="ISO",host="localhost")
queryResult <- dbGetQuery(con, "fetch something...")
dbDisconnect(con)
return(queryResult)
}
stopCluster(cl)
但是,现在您必须考虑每隔foreach
次迭代创建和断开新连接。因此,您可能会产生一些性能开销。显然,您可以通过智能地分割查询/数据来避免这种情况,以便在同一次迭代期间完成大量工作。理想情况下,您应该将工作分成尽可能多的核心。