Python 3.x 多进程上下文中SQLAlchemy(SQLite3引擎)的互斥问题
我有一个SQLite3表,其中有很多行,很多进程都会尝试使用这些行。每条生产线只能被一个过程消耗。为了确保互斥性,我给每个进程分配了id,给每个DB行分配了一列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,一些行被多个进程占用。以下是我实施测试的方式:
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