我具有一个简单的函数,可以在sqlite表中写入某些计算的输出。我想在Python中使用多处理并行使用此功能。我的具体问题是,当每个过程试图将结果写入同一表中时,如何避免冲突?运行代码给我这个错误:sqlite3.erationalerrationerror:数据库已锁定。
import sqlite3
from multiprocessing import Pool
conn = sqlite3.connect('test.db')
c = conn.cursor()
c.execute("CREATE TABLE table_1 (id int,output int)")
def write_to_file(a_tuple):
index = a_tuple[0]
input = a_tuple[1]
output = input + 1
c.execute('INSERT INTO table_1 (id, output)' 'VALUES (?,?)', (index,output))
if __name__ == "__main__":
p = Pool()
results = p.map(write_to_file, [(1,10),(2,11),(3,13),(4,14)])
p.close()
p.join()
Traceback (most recent call last):
sqlite3.OperationalError: database is locked
使用Pool
是个好主意。
我看到了这个问题的三个可能的解决方案。
首先,不要让泳池工作者试图将数据插入数据库,而是让工作人员将数据返回到父程。
在父进程中,使用imap_unordered
代替map
。这是一种疑惑,一旦获得值就开始提供值。父母可以将数据插入数据库。
这将序列化访问数据库,防止问题。
如果要插入数据库中的数据相对较小,则该解决方案将是优选的,但是更新经常发生。因此,如果要更新数据库的时间比计算数据相同或更多的时间。
。第二,您可以使用Lock
。一名工人应该
- 获取锁,
- 打开数据库,
- 插入值,
- 关闭数据库,
- 释放锁。
这将避免将数据发送到父进程的开销。但是,相反,您可能会让工人停下来等待将数据写入数据库。
,如果要插入的数据量为大,那么这将是一个首选的解决方案,但是计算数据所需的时间比将其插入数据库所需的时间更长。
。第三,您可以让每个工人写入自己的数据库,然后将其合并。您可以直接在SQLite甚至Python中进行此操作。尽管有大量数据,但我不确定后者是否有优势。
数据库已锁定以保护您的数据免受损坏。
我相信您不能同时拥有许多流程来访问相同的数据库,至少没有
conn = sqlite3.connect('test.db')
c = conn.cursor()
如果每个过程都必须访问数据库,则应考虑至少关闭cursor
对象c
(也许严格严格地,connect
对象conn
(在每个过程中并重新打开该过程。不知何故,其他进程需要等待当前的过程才能释放锁,然后才能获取锁。(有很多方法可以实现等待(。
将isolation_level
设置为'EXCLUSIVE'
为我修复:
conn = sqlite3.connect('test.db', isolation_level='EXCLUSIVE')