【问题标题】:foreach %dopar% + RPostgreSQLforeach %dopar% + RPostgreSQL
【发布时间】:2011-04-23 14:24:27
【问题描述】:

我正在使用 RPostgreSQL 连接到本地数据库。该设置在我的 Linux 机器上运行良好。 R 2.11.1,Postgres 8.4。

我正在使用带有多核 (doMC) 并行后端的“foreach”来包装一些重复查询(编号为几千)并将结果附加到数据结构中。奇怪的是,如果我使用 %do% 则它可以工作,但当我切换到 %dopar% 时它会失败,但只有一次迭代时例外(如下所示)

我想知道它是否与单个连接对象有关,因此我创建了 10 个连接对象,并根据“i”是什么,为该查询提供了某个 con 对象,具体取决于 i 模 10。(表示下面只有 2 个连接对象)。评估 eval(expr.01) 的表达式包含/是取决于“i”是什么的查询。

我无法理解这些特定的错误消息。我想知道是否有任何方法可以使这项工作。

谢谢。
Vishal Belsare

R sn-p 如下:

> id.qed2.foreach <- foreach(i = 1588:1588, .inorder=FALSE) %dopar% { 
+ if (i %% 2 == 0) {con <- con0}; 
+ if (i %% 2 == 1) {con <- con1}; 
+ fetch(dbSendQuery(con,eval(expr.01)),n=-1)$idreuters};
> id.qed2.foreach
[[1]]
  [1]   411   414  2140  2406  4490  4507  4519  4570  4571  4572  4703  4731
[109] 48765 84312 91797

> id.qed2.foreach <- foreach(i = 1588:1589, .inorder=FALSE) %dopar% { 
+ if (i %% 2 == 0) {con <- con0}; 
+ if (i %% 2 == 1) {con <- con1}; 
+ fetch(dbSendQuery(con,eval(expr.01)),n=-1)$idreuters};
Error in stop(paste("expired", class(con))) : 
  no function to return from, jumping to top level
Error in stop(paste("expired", class(con))) : 
  no function to return from, jumping to top level
Error in { : 
  task 1 failed - "error in evaluating the argument 'res' in selecting a method for function 'fetch'"
> 

编辑:我改变了一些东西,(仍然不成功),但有一些事情浮出水面。在循环中建立的连接对象,而不是通过 dbDisconnect '断开',导致连接挂起,如 Postgres 的 /var/log 所示。执行此操作时会显示一些新的错误消息:

> system.time(
+ id.qed2.foreach <- foreach(i = 1588:1590, .inorder=FALSE, 
.packages=c("DBI", "RPostgreSQL")) %dopar% {drv0 <- dbDriver("PostgreSQL"); 
con0 <- dbConnect(drv0, dbname='nseindia');
list(idreuters=fetch(dbSendQuery(con0,eval(expr.01)),n=-1)$idreuters);
dbDisconnect(con0)})
Error in postgresqlExecStatement(conn, statement, ...) : 
  no function to return from, jumping to top level
Error in postgresqlExecStatement(conn, statement, ...) : 
  no function to return from, jumping to top level
Error in postgresqlExecStatement(conn, statement, ...) : 
  no function to return from, jumping to top level
Error in { : 
  task 1 failed - "error in evaluating the argument 'res' in selecting a method for function 'fetch'"

【问题讨论】:

  • 如果您解决了,请将您的解决方案作为答案发布在下面并标记为已接受。对以后的参考很有用。

标签: postgresql r foreach parallel-processing


【解决方案1】:

每个工作人员创建一次数据库连接比每个任务创建一次更有效。不幸的是,mclapply 没有提供在执行任务之前初始化worker 的机制,所以使用doMC 后端来做这件事并不容易,但是如果你使用doParallel 后端,你可以使用clusterEvalQ 来初始化worker。以下是如何重构代码的示例:

library(doParallel)
cl <- makePSOCKcluster(detectCores())
registerDoParallel(cl)

clusterEvalQ(cl, {
  library(DBI)
  library(RPostgreSQL)
  drv <- dbDriver("PostgreSQL")
  con <- dbConnect(drv, dbname="nsdq")
  NULL
})

id.qed.foreach <- foreach(i=1588:3638, .inorder=FALSE,
                          .noexport="con",
                          .packages=c("DBI", "RPostgreSQL")) %dopar% {
  lst <- eval(expr.01)  #contains the SQL query which depends on 'i'
  qry <- dbSendQuery(con, lst)
  tmp <- fetch(qry, n=-1)
  dt <- dates.qed2[i]
  list(date=dt, idreuters=tmp$idreuters)
}

clusterEvalQ(cl, {
  dbDisconnect(con)
})

由于 doParallel 和 clusterEvalQ 使用相同的集群对象 cl,因此在执行任务时,foreach 循环将可以访问数据库连接对象 con

【讨论】:

  • 史蒂夫,这很有帮助。想知道你是怎么得到这个相当古老的问题的!
  • 有没有办法使用foreach将数据库设置代码传递给每个worker?我想尝试将此代码与任意并行后端一起使用。
  • @Zach 没有后端独立的方法来初始化工作人员,这一直困扰着我。我已经尝试过特定于后端的机制(例如在 doMPI 中),但这从未变成通用功能,部分原因是由于 mclapply 不支持工作程序初始化,因此使用 doMC 的实现可能会非常难看。
  • @SteveWeston 你发布这个答案已经有一段时间了,但我希望你仍然会看到这个,因为它是我发现的与我有预配置连接的问题最接近的一个(并希望准备好的陈述)在每个工人中。我尝试了您的代码,修改为使用 R 包“odbc”而不是 PostgreSQL 作为数据库。我得到“{ 中的错误:任务 1 失败 - “外部指针无效””我所做的只是在 foreach 循环中从 MyTable 中进行简单的选择计数(*)。知道有什么问题吗?
  • @colonel.triq 如果您在 master 的全局环境中定义了“con”(我的示例没有),那么它将自动导出给工作人员并导致错误。我在示例中添加了“.noexport”选项以防止这种情况发生,即使在我的情况下这不是问题。我建议您使用 foreach .verbose=TRUE 选项来查看是否会自动导出任何意外情况,因为您的错误消息表明自动导出并使用了不应该使用的内容。
【解决方案2】:

以下工作和速度比顺序形式提高了约 1.5 倍。作为下一步,我想知道是否可以将连接对象附加到由 registerDoMC 生成的每个工作人员。如果是这样,那么就不需要创建/销毁连接对象,这样可以防止 PostgreSQL 服务器的连接不堪重负。

pgparquery <- function(i) {
drv <- dbDriver("PostgreSQL"); 
con <- dbConnect(drv, dbname='nsdq'); 
lst <- eval(expr.01); #contains the SQL query which depends on 'i'
qry <- dbSendQuery(con,lst);
tmp <- fetch(qry,n=-1);
dt <- dates.qed2[i]
dbDisconnect(con);
result <- list(date=dt, idreuters=tmp$idreuters)
return(result)}

id.qed.foreach <- foreach(i = 1588:3638, .inorder=FALSE, .packages=c("DBI", "RPostgreSQL")) %dopar% {pgparquery(i)}

--
Vishal Belsare

【讨论】:

  • Vishal,你有没有想过如何按照上面的描述将持久连接对象附加到每个工作人员?我也遇到过这个问题。有趣的是,我能够让 dbListTables(conn) 在工作人员身上工作,但 dbgetQuery(conn, ...) 类型的命令似乎不适用于附加的连接对象。
  • @Noah 您可以尝试使用我在回答中描述的技术。
猜你喜欢
  • 2018-07-13
  • 1970-01-01
  • 1970-01-01
  • 2016-08-02
  • 1970-01-01
  • 1970-01-01
  • 2019-07-03
  • 2013-06-02
  • 2011-10-11
相关资源
最近更新 更多