Python3.x如何在进程之间共享数据库连接?

Posted

技术标签:

【中文标题】Python3.x如何在进程之间共享数据库连接?【英文标题】:Python3.x how to share a database connection between processes? 【发布时间】:2015-04-22 17:16:37 【问题描述】:

我正在使用 multiprocessing.Pool 运行多个进程

每个进程都必须查询我的 mysql 数据库。

我目前连接数据库一次,然后在进程之间共享连接

它可以工作,但偶尔会出现奇怪的错误。我已经确认是查询数据库时出现的错误。

我认为问题是因为所有进程都使用相同的连接。

正确吗?

当我寻找答案时,我偶然发现了这个问答 How to share a single MySQL database connection between multiple processes in Python

所以我查了 Class pooling.MySQLConnectionPool

http://dev.mysql.com/doc/connector-python/en/connector-python-connection-pooling.html http://dev.mysql.com/doc/connector-python/en/connector-python-api-mysqlconnectionpool.html http://dev.mysql.com/doc/connector-python/en/connector-python-api-pooledmysqlconnection.html

如果我明白这一点。我将设置一个包含多个连接的池并在进程之间共享该池。然后每个进程将查看该池,如果有可用连接,则使用它,否则等待连接被释放。

正确吗?

但后来我发现了这个问答 Accessing a MySQL connection pool from Python multiprocessing

“mata”似乎首先证实了我的怀疑,但同时他驳斥了设置一个在进程之间共享的池的使用

在不同进程之间共享数据库连接(或连接池)是个坏主意(我非常怀疑它是否能正常工作),

相反,他建议

所以每个使用它自己的连接的进程实际上是你应该瞄准的。

这是什么意思?

我应该为每个工作人员创建一个连接吗? 那么mysql池有什么用呢?

mata 在他的回答中给出的例子似乎很合理,但我不明白整个池作为 init 参数的传递

p = Pool(initializer=init)
为什么?(正如 ph_singer 在 cmets 中指出的那样,这不是一个好的解决方案)

将阻塞的 Pool.map() 方法更改为 Pool.map_async() 并将连接从池发送到 map_async(q, ConnObj) 就足够了?

正确吗?

在 cmets 中提到

使用具有多个进程的单个池的唯一方法是拥有一个专用进程,该进程使用队列与所有数据库访问进行通信

更新 找到这个。似乎同意:https://***.com/a/26072257/1267259

如果您需要大量并发工作人员,但他们并不一直使用数据库,那么您应该拥有一组数据库工作进程来处理所有数据库访问并与其他工作进程交换数据。每个数据库工作进程都有一个数据库连接。其他进程仅通过您的数据库工作者与数据库对话。

Python 的多处理队列、fifo 等为此提供了适当的消息传递功能。

这真的正确吗?

mysql 池的目的不是处理进程的请求并将它们中继到可用的连接吗?

现在我很困惑......

【问题讨论】:

你读过the documentation关于这个吗?基本上,这个想法是在主进程中创建一个连接池,然后在每个衍生的线程/进程中,您从该池中请求连接。线程不应该共享相同的连接,因为这样线程可以相互阻止线程应该帮助的主要活动之一:IO。 另一种非常好的方法是将请求连接的代码仅放在代码的线程/进程特定部分中,以便每个线程都有自己的连接(以及其中隐含的“池” case 是实际的数据库驱动程序本身,它支持并发连接)。特别是对于那些只需要快速连接以独立于其他进程/线程来查询数据的令人尴尬的并行问题,这是有道理的。但是,您失去的是对连接总数和(与带有 ISAM 的 MySQL 无关)事务管理的显式控制。 "为什么使用 [db connections] 池" -- 如果您的工作进程中有多个 线程,那么该池可能很有用(几个线程可以并行读取/写入数据(CPython 可以在 I/O 期间释放 GIL)。如果每个工作进程只有一个线程,那么没有必要使用数据库池。 @user1267259:没有。这是我之前提到的基本误解:“不要在进程之间传递池”——大多数池实现不能传递(并且他们不应该)。从每个进程的单个 db 连接开始(或者如果其中有多个 db 交互线程,则在工作进程中创建 inside 的 db 连接池) -- if它会中断然后准确描述您的具体情况。 @user1267259:是的。它们是有区别的。但没关系。你也不应该这样做。你什么都没通过。如果需要,每个子进程都会创建自己的数据库连接(单独或作为池)。 【参考方案1】:

找到Share connection to postgres db across processes in Python 我的第一个问题的答案似乎是

您不能在这样的进程之间合理地共享数据库连接。你可以在线程之间共享一个连接,但前提是你要确保连接一次只被一个线程使用。这在进程之间不起作用,因为连接的客户端状态存储在客户端的地址空间中。

我剩下的问题的答案基本上归结为您使用以下哪个陈述(来自本问答中 cmets 的讨论)

基本上,这个想法是在主进程中创建一个连接池,然后在每个衍生的线程/进程中,您从该池中请求连接。线程不应该共享相同的连接,因为线程可以相互阻止线程应该帮助的主要活动之一:IO。 ——F先生

不将池或从池中的连接传递给子进程

如果需要,每个子进程都会创建自己的数据库连接(单独或作为池)——J.F. Sebastian。

“为什么使用 [db connections] 池”——如果您的工作进程中有多个线程,那么该池可能很有用(多个线程可以并行读取/写入数据(CPython 可以在 I/O 期间释放 GIL)) .如果每个工作进程只有一个线程,则没有必要使用数据库池。 ——J.F.塞巴斯蒂安


附注

这并不能完全回答我的第三个问题,但它确实表明在某些情况下为每个进程创建一个连接是可行的 (Share connection to postgres db across processes in Python)

目前尚不清楚您要在这里寻找什么。 5个连接当然不是问题。您是说您最终可能需要生成 100 或 1000 个进程,每个进程都有自己的连接?如果是这样,即使您可以共享它们,它们也会被绑定到连接池,因为在任何给定时间只有一个进程可以使用给定连接。 – 坎普森 2014 年 9 月 27 日在 5:19

【讨论】:

很棒的总结。关于最后一句话,我认为它是不正确的。从最后一句话:“即使你可以共享它们,它们也会被绑定到连接池,因为在任何给定时间只有一个进程可以使用给定连接”这不可能是正确的。每个进程都创建自己的池,一个进程的池中的连接获取对进程是不可见的。所以两个进程可以同时写请求,互相破坏。 连接池似乎存在,至少从psycopg docs 来看,是为了在线程之间共享连接。正如它所说,创建连接可能是一项昂贵的任务,因此可以通过使用池来避免这种成本。它看起来像是在进程之间共享连接的一个很好的解决方案,但是文档还说连接shouldn’t be used by a forked processes。那么我会说最好的解决方案是马耳他的解决方案。 你采用了什么方法?马耳他的(无池)解决方案有什么缺点吗?

以上是关于Python3.x如何在进程之间共享数据库连接?的主要内容,如果未能解决你的问题,请参考以下文章

辅助库可以用于在不相关的进程(不是分叉的进程)之间共享接受的连接吗?

如何在两个进程之间共享数据?

如何查看哪些进程在使用共享内存

如何在不重复的情况下在进程之间共享大量数据? (IPC)

使用队列实现进程之间的数据共享

在多对多连接表中,如何计算两个“所有者”共享的条目数?