gpt4 book ai didi

python - Python 中的基本并发 SQLite 编写器

转载 作者:行者123 更新时间:2023-12-01 01:30:16 30 4
gpt4 key购买 nike

我创建了一个非常基本的脚本,定期将一些数据写入数据库:

测试.py

import sqlite3
import sys
import time

DB_CREATE_TABLE = 'CREATE TABLE IF NOT EXISTS items (item TEXT)'
DB_INSERT = 'INSERT INTO items VALUES (?)'
FILENAME = 'test.db'


def main():
index = int()
c = sqlite3.connect(FILENAME)
c.execute(DB_CREATE_TABLE)
c.commit()

while True:
item = '{name}_{index}'.format(name=sys.argv[1], index=index)
c.execute(DB_INSERT, (item,))
c.commit()
time.sleep(1)
index += 1

c.close()


if __name__ == '__main__':
main()

现在我可以通过多次运行脚本来实现简单的并发:

python3 test.py foo &
python3 test.py bar &

我尝试阅读一些有关脚本同时写入同一数据库文件的文章,但我仍然不确定我的脚本将如何处理此类事件,并且我不知道如何测试它。

我的期望是,在不太可能发生的情况下,当我的脚本的两个实例尝试在同一毫秒内写入数据库时​​,后一个实例将简单地默默等待,直到较早的实例完成其工作。

我当前的实现是否满足我的期望?如果没有,发生此类事件时它会如何表现以及如何修复它?

最佳答案

TL;DR

此脚本满足预期。

说明

当两个脚本实例尝试同时写入的罕见事件发生时,第一个脚本实例会锁定数据库,而第二个脚本实例会静默等待一段时间,直到第一个脚本实例完成其事务,以便解锁数据库以进行写入再次。

更准确地说,第二个脚本实例等待 5 秒(默认情况下),然后引发 OperationalError 并显示消息数据库已锁定。正如 @roganjosh 评论的那样,这种行为实际上是 Python SQLite 包装器特有的。文档states :

When a database is accessed by multiple connections, and one of the processes modifies the database, the SQLite database is locked until that transaction is committed. The timeout parameter specifies how long the connection should wait for the lock to go away until raising an exception. The default for the timeout parameter is 5.0 (five seconds).

测试

为了演示两个实例的碰撞事件,我修改了 main 函数:

def main():
c = sqlite3.connect(FILENAME)
c.execute(DB_CREATE_TABLE)
c.commit()
print('{} {}: {}'.format(time.time(), sys.argv[1], 'trying to insert ...'))

try:
c.execute(DB_INSERT, (sys.argv[1],))
except sqlite3.OperationalError as e:
print('{} {}: {}'.format(time.time(), sys.argv[1], e))
return

time.sleep(int(sys.argv[2]))
c.commit()
print('{} {}: {}'.format(time.time(), sys.argv[1], 'done'))
c.close()

文档指出数据库将被锁定,直到事务提交为止。因此,只需在交易期间 sleep 就足以测试它。

测试 1

我们运行以下命令:

python3 test.py first 10 & sleep 1 && python3 test.py second 0

第一个实例正在运行,1 秒后第二个实例正在运行。第一个实例创建一个 10 秒长的事务,在此期间第二个实例尝试写入数据库、等待然后引发异常。该日志表明:

1540307088.6203635 first: trying to insert ...
1540307089.6155508 second: trying to insert ...
1540307094.6333485 second: database is locked
1540307098.6353421 first: done

测试 2

我们运行以下命令:

python3 test.py first 3 & sleep 1 && python3 test.py second 0

第一个实例正在运行,1 秒后第二个实例正在运行。第一个实例创建一个 3 秒长的事务,在此期间第二个实例尝试写入数据库并等待。由于它是在 1 秒后创建的,因此必须等待 3 秒 - 1 秒 = 2 秒,这小于默认的 5 秒,因此两个事务都会成功完成。该日志表明:

1540307132.2834115 first: trying to insert ...
1540307133.2811155 second: trying to insert ...
1540307135.2912169 first: done
1540307135.3217440 second: done

结论

事务完成所需的时间(毫秒)明显小于锁定时间限制(5 秒),因此在这种情况下,脚本确实符合预期。但正如@HarlyH。评论说,事务在队列中等待提交,因此对于频繁使用或非常大的数据库来说,这不是一个好的解决方案,因为与数据库的通信会变慢。

关于python - Python 中的基本并发 SQLite 编写器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52943998/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com