python - os.fork() 之后的共享对象

标签 python unix multiprocessing

在使用多个进程与数据库交互时,我遇到了一些奇怪的应用程序行为。我正在使用 Linux。

我有自己的 QueryExecutor 实现,它在其生命周期内使用单个连接:

class QueryExecutor(object):
    def __init__(self, db_conf):
        self._db_config = db_conf
        self._conn = self._get_connection()

    def execute_query(self, query):
        # some code
    # some more code

def query_executor():
    global _QUERY_EXECUTOR
    if _QUERY_EXECUTOR is None:
        _QUERY_EXECUTOR = QueryExecutor(some_db_config)
    return _QUERY_EXECUTOR

Query Executor 在实例化后永远不会被修改。

最初只有一个进程,它会时不时地 fork (os.fork()) 几次。新进程是执行一些任务然后退出的 worker 。每个工作人员都调用 query_executor() 来执行 SQL 查询。

我发现sql查询经常返回错误的结果(好像有时候sql查询结果返回到错误的进程)。唯一合理的解释是所有进程共享相同的 sql 连接(根据 MySQLdb 文档:threadsafety = 1 线程可以共享模块,但不能共享连接)。

不知道是什么OS机制导致了这种情况。据我所知,在 Linux 上,当进程 fork 时,父进程的页面不会为子进程复制,它们由两个进程共享,直到其中一个尝试修改某些页面(写时复制).正如我之前提到的,QueryExecutor 对象在创建后保持不变。我想这就是所有进程使用相同的 QueryExecutor 实例并因此使用相同的 sql 连接的原因。

我是对的还是我错过了什么?你有什么建议吗?

提前致谢!

格热戈日

最佳答案

问题的根源在于fork()只是创建了一个进程的完全独立的副本,但这两个进程share opened files, sockets and pipes .这就是为什么 MySQL 服务器写入的任何数据可能 [正确] 只能从单个进程读取,如果两个进程尝试发出请求并读取响应,那么它们很可能会相互干扰工作。这与“多线程”无关,因为在多线程的情况下,只有一个进程和很少的执行线程,它们共享数据并可以协调。

使用fork() 的正确方法是close (或重新打开)在除进程的一个副本之外的所有文件句柄类对象之后立即 fork ,或者至少避免在多个进程中使用它们。

关于python - os.fork() 之后的共享对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23385700/

相关文章:

regex - Awk:仅在 2 个或更多空间上拆分

python - 字符串作为具有多处理访问的发送缓冲区

python - python 中的多处理,处理多个文件

python - cur.executemany 在字符串格式化期间并非所有参数都已转换

linux - 查找最大值和最小值并打印文件中的行

python - 确认用户所做的更改

unix - NF > 0 在 UNIX 编程环境中检查两次

python - 如何为不同Python进程之间的不同神经网络设置共享权重?

python - 如何编写一个从列表中递归删除字符实例的函数?

python - 为什么 Psycopg2 很难在 CSV 中解析我的逗号