使用dplyr或pool并行处理和查询SQL:MySQL服务器已经消失

使用dplyr或pool并行处理和查询SQL:MySQL服务器已经消失,mysql,r,parallel-processing,Mysql,R,Parallel Processing,前面有几个相关问题,但没有一个能解决我的问题: 我的用例如下:我有一个需要打印的数据的大数据库。由于对数据和绘图本身进行了一些必要的预处理(ggplot2),每个绘图都需要几秒钟的时间来创建。我需要做大量的绘图。我的想法是,我将通过dplyr连接到数据库,而无需将所有数据下载到内存中。然后我有一个函数,它获取要绘制的数据子集。这种方法在使用单线程时效果很好,但是当我尝试使用并行处理时,我遇到了与连接相关的SQL错误MySQL服务器已经消失了 现在,在这种情况下,解决方案只是终止函数中的

前面有几个相关问题,但没有一个能解决我的问题:

我的用例如下:我有一个需要打印的数据的大数据库。由于对数据和绘图本身进行了一些必要的预处理(ggplot2),每个绘图都需要几秒钟的时间来创建。我需要做大量的绘图。我的想法是,我将通过dplyr连接到数据库,而无需将所有数据下载到内存中。然后我有一个函数,它获取要绘制的数据子集。这种方法在使用单线程时效果很好,但是当我尝试使用并行处理时,我遇到了与连接相关的SQL错误
MySQL服务器已经消失了

现在,在这种情况下,解决方案只是终止函数中的当前连接,这迫使建立一个新连接。我是用
connection.close()
实现的,其中
connection
来自Django的
Django.db

我的问题是,我找不到这种方法的R等价物。当我找到R的包时,我认为我已经找到了解决方案:

此包支持为各种类型的对象创建对象池 对象,以降低获取对象的计算成本。 目前唯一受支持的池对象是
DBI
连接(请参阅
DBI
程序包以获取更多信息),可用于查询数据库 直接通过
DBI
或通过
dplyr
。但是,
类 通用性足以允许任何R对象的池,前提是 有人适当地实现了后端(创建对象 工厂类和所有必需的方法)--带有 有关如何操作的说明将很快发布

我的代码太大,无法在此处发布,但本质上是这样的:

#libraries loaded as necessary

#connect to the db in some kind of way
#with dplyr
db = src_mysql(db_database, username = db_username, password = db_password) 
#with RMySQL directly
db = dbConnect(RMySQL::MySQL(), dbname = db_database, username = db_username, password = db_password)
#with pool
db = pool::dbPool(RMySQL::MySQL(), 
                  dbname = db_database, 
                  username = db_username, 
                  password = db_password, 
                  minSize = 4)
#I tried all 3

#connect to a table
some_large_table = tbl(db, 'table')

#define the function
some_function = function(some_id) {
    #fetch data from table
    subtable = some_large_table %>% filter(id == some_id) %>% collect()

    #do something with the data
    something(subtable)
}

#parallel process
mclapply(vector_of_ids,
         FUN = some_function,
         mc.cores = num_of_threads)

上面的代码与Python代码不同,这就是关键区别。您在Python中所做的一切在R中是完全可能的(请参见下面的MWE)。但是,您上面的代码不是:

终止函数中的当前连接,从而强制建立新连接

它尝试(但失败)的是使数据库连接从父进程传输到调用
mclappy
打开的每个子进程。这是不可能的。无论发生什么情况,数据库连接都不能跨越进程边界

这是一个更一般的“规则”的示例,即子进程不能影响父进程的状态period。例如,子进程也不能写入内存位置。您也不能从这些子进程打印(到父进程的图形设备)

为了执行与Python中相同的操作,如果希望函数真正并行,则需要在函数
FUN
(mclappy的第二个参数)内部打开一个新连接。也就是说,您必须确保
dbConnect
调用发生在子进程内部

这消除了
(尽管使用起来非常安全),因为
在重用连接时非常有用,并且通常希望它们易于访问。对于您的并行用例,由于您不能跨越流程边界,这是无用的:您将始终需要打开和关闭每个新流程的连接,因此您最好完全跳过

以下是Python解决方案到R的正确“翻译”:

library(dplyr)

getById <- function(id) {
  # create a connection and close it on exit
  conn <- DBI::dbConnect(
    drv = RMySQL::MySQL(),
    dbname = "shinydemo",
    host = "shiny-demo.csa7qlmguqrf.us-east-1.rds.amazonaws.com",
    username = "guest",
    password = "guest"
  )
  on.exit(DBI::dbDisconnect(conn))

  # get a specific row based on ID
  conn %>% tbl("City") %>% filter(ID == id) %>% collect()
}

parallel::mclapply(1:10, getById, mc.cores = 12)
库(dplyr)
getById%筛选器(ID==ID)%%>%collect()
}
并行::mclapply(1:10,getById,mc.cores=12)