我有一个简单的函数,它将一些计算的输出写入sqlite表中。我想在Python中使用多处理并行使用此函数。我的具体问题是当每个进程尝试将其结果写入同一个表时如何避免冲突?运行代码会给我这个错误:sqlite3.OperationalError:数据库被锁定。
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
答案 0 :(得分:4)
使用Pool
是一个好主意。
我看到了解决这个问题的三种可能方法。
首先,不要让池工作者尝试将数据插入数据库,而是让工作人员将数据返回到父进程。
在父进程中,使用imap_unordered
代替map
。
这是一个可迭代的,一旦可用就开始提供值。父级可以将数据插入数据库。
这将序列化对数据库的访问,防止出现问题。
如果要插入数据库的数据相对较小,则此解决方案将是首选,但更新经常发生。因此,如果更新数据库所需的时间与计算数据相同或更长。
其次,您可以使用Lock
。那么工人应该
这将避免将数据发送到父进程的开销。但相反,你可能会让工人停下来等待将数据写入数据库。
如果要插入的数据量 large ,这将是首选解决方案,但计算数据所需的时间要比将数据插入数据库要长得多。
第三,您可以让每个工作者写入自己的数据库,然后合并它们。您可以directly in sqlite甚至in Python执行此操作。虽然有大量数据我不确定后者是否有优势。
答案 1 :(得分:1)
数据库已被锁定以保护您的数据免受损坏。
我相信你不能让很多进程同时访问同一个数据库,至少不能用
conn = sqlite3.connect('test.db')
c = conn.cursor()
如果每个进程都必须访问数据库,您应该考虑至少关闭cursor
对象c
(可能不太严格,connect
对象conn
)每个流程,并在流程再次需要时重新打开它。不知何故,其他进程需要等待当前进程释放锁,然后另一个进程才能获得锁。 (有很多方法可以实现等待)。
答案 2 :(得分:1)
将isolation_level
设置为'EXCLUSIVE'
可以为我修复:
conn = sqlite3.connect('test.db', isolation_level='EXCLUSIVE')