(已解决)python multiprocess 多进程操作mysql时丢失数据

背景

用python multiprocess 开了100个进程写数据库,共享一个链接
发现有时候 遗漏数据 不报错

lock.acquire()
conn.execute(sql)
lock.release()

当改成单独链接的时候报错

Deadlock found when trying to get lock; try restarting transaction

隔天来更

头疼啊……
参考
Share connection to postgres db across processes in Python

(已解决)python multiprocess 多进程操作mysql时丢失数据_第1张图片

reason

使用连接池和使用 Engine 创建通过 create_engine() ,集合连接 不与分叉进程共享 . TCP连接表示为文件描述符,通常跨进程边界工作,这意味着这将导致代表两个或更多完全独立的Python解释器状态并发访问文件描述符

solution

Engine Configuration

数据库engine

在单进程中,建议在在初始化的模块的时候创建Engine, 使Engine成为全局变量, 而不是为每个调用Engine的对象或者函数中创建, Engine不同于connect, connect函数会创建数据库连接的资源,Engine是管理connect创建的连接资源

在多进程中,为每个子进程都创建各自的Engine, 因为进程之间是不能共享Engine

一语惊醒梦中人!

sqlalchemy-core

有两种方法可以解决这个问题。

首先,要么创建一个新的 Engine 在子进程内,或在现有进程上 Engine ,调用 Engine.dispose() 在子进程使用任何连接之前。这将从池中删除所有现有连接,以便生成所有新连接。下面是使用 multiprocessing.Process 但是这个想法应该适应使用中的分叉样式

engine = create_engine("...")

def run_in_process():
  engine.dispose()

  with engine.connect() as conn:
      conn.execute("...")

p = Process(target=run_in_process

下一种方法是 Pool 它本身带有事件,以便连接在子进程中自动失效。这有点神奇,但可能更简单:

from sqlalchemy import event
from sqlalchemy import exc
import os

engine = create_engine("...")

@event.listens_for(engine, "connect")
def connect(dbapi_connection, connection_record):
    connection_record.info['pid'] = os.getpid()

@event.listens_for(engine, "checkout")
def checkout(dbapi_connection, connection_record, connection_proxy):
    pid = os.getpid()
    if connection_record.info['pid'] != pid:
        connection_record.connection = connection_proxy.connection = None
        raise exc.DisconnectionError(
                "Connection record belongs to pid %s, "
                "attempting to check out in pid %s" %
                (connection_record.info['pid'], pid)
        )

你可能感兴趣的:(mysql)