Python 3.x 多进程上下文中SQLAlchemy(SQLite3引擎)的互斥问题

Python 3.x 多进程上下文中SQLAlchemy(SQLite3引擎)的互斥问题,python-3.x,concurrency,sqlite,sqlalchemy,Python 3.x,Concurrency,Sqlite,Sqlalchemy,我有一个SQLite3表,其中有很多行,很多进程都会尝试使用这些行。每条生产线只能被一个过程消耗。为了确保互斥性,我给每个进程分配了id,给每个DB行分配了一列consumered\u,指示哪个进程使用了它 因此,我的锁定机制包括启动一个事务,获取一行被消费的\u为空,将列更新为进程的id,并提交事务。如果两个进程试图获取同一行,序列化原则将确保其中只有一个进程可以提交事务 使用纯sqlite,我成功地应用了这个锁定概念,但使用SQLAlchemy,一些行被多个进程占用。以下是我实施测试的方式:

我有一个SQLite3表,其中有很多行,很多进程都会尝试使用这些行。每条生产线只能被一个过程消耗。为了确保互斥性,我给每个进程分配了id,给每个DB行分配了一列
consumered\u,指示哪个进程使用了它

因此,我的锁定机制包括启动一个事务,获取一行
消费的\u为空,将列更新为进程的id,并提交事务。如果两个进程试图获取同一行,序列化原则将确保其中只有一个进程可以提交事务

使用纯sqlite,我成功地应用了这个锁定概念,但使用SQLAlchemy,一些行被多个进程占用。以下是我实施测试的方式:

我有以下课程:

class ToConsume(Base):
    __tablename__ = 'to_consume'
    id = Column(Integer, primary_key=True)
    consumed_by = Column(Integer,nullable=True)
我有100个不同进程调用的以下函数:

def consume(id):
    log = open("log/"+str(id),"w")
    while True:
        session = None
        try:
            session = Session()
            consume = session.query(ToConsume).filter_by(consumed_by=None).first()
            if consume is None:
                break
            consume.consumed_by = id
            session.commit()
            log.write(str(consume.id)+"\n")
            log.flush()
        except Exception:
            if session is not None:
                session.rollback()
    log.close()
在文件的开头,我以以下方式初始化了SQLAlchemy:

engine = sqlalchemy.create_engine('sqlite:///multithread.db', echo=False,connect_args={'timeout': 30})
def _sqlite_pragmas(dbapi_con, con_record):
    dbapi_con.execute('PRAGMA synchronous = 0;')
sqlalchemy.event.listen(engine, 'connect', _sqlite_pragmas)

Base = sqlalchemy.ext.declarative.declarative_base()
Session = sqlalchemy.orm.sessionmaker(bind=engine)
我的数据库从1000行开始。运行100个独立的python进程(我没有使用线程),我希望所有日志文件的串联将产生1000行,但我得到了3000多行


我很难理解为什么在使用SQLAlchemy时我的互斥不起作用。请注意,当我使用纯sqlite时,问题不会发生。

默认情况下,sqlite未设置为可序列化。此外,PythonSQLite3驱动程序中也存在bug(请参阅了解背景)。要将可序列化隔离与sqlite3/sqlalchemy一起使用,请参阅。例如:

from sqlalchemy import create_engine, event

engine = create_engine("sqlite:///myfile.db", isolation_level='SERIALIZABLE')

@event.listens_for(engine, "begin")
def do_begin(conn):
    conn.execute("BEGIN")

您实际得到了哪些异常?当您使用mysql时,是否也会发生同样的情况?(请注意,您可能需要在mysql中适当地设置排除级别。)如果删除PRAGMA/将其设置为1会发生什么?我没有得到任何异常,查看我的日志文件,我注意到同一行被多个进程占用。我没有使用mysql进行测试,但使用纯SQLite实现相同的逻辑不会出现问题。更改pragma只会使事情变得更慢,但不会影响同一行被多个进程占用的事实。很抱歉,花了太长时间才给您奖金,我误解了stackoveflow UI