import sqlite3
conn = sqlite3.connect('output.db')
count = 0
items = []
for item in InfStream: # assume I have an infinite stream
items.append((item,))
count += 1
if count == 10000:
conn.executemany("INSERT INTO table VALUES (?)", items)
conn.commit()
items = []
在这个Python代码中,我有一个名为InfStream的未知长度的流来自API,我想将流中的项插入到sqlite数据库中的表中。在这种情况下,我首先创建一个包含10,000个项目的列表,然后使用executemany插入到数据库中。这将需要大约1小时。但是,代码有问题,当executemany运行时,我必须等待大约15秒才能完成。在我的情况下,这是不可接受的,因为我需要继续从流中获取项目,否则如果我延迟太久就会断开连接。
我想在executemany同时运行时循环继续。是否可以这样做?
NB。输入远比写入慢。输入的10,000个项目大约需要1个小时,输出只需15秒。
答案 0 :(得分:4)
这是一个经典的Producer–consumer problem,最好使用Queue来处理。
在这种情况下,制作人是你的InfStream,而消费者就是你阻止的所有内容。
将您的顺序代码转换为多线程生产者 - 消费者模型并使用队列在线程之间调度数据将是直接的
考虑您的代码
import sqlite3
conn = sqlite3.connect('output.db')
count = 0
items = []
for item in InfStream: # assume I have an infinite stream
items.append((item,))
count += 1
if count == 10000:
conn.executemany("INSERT INTO table VALUES (?)", items)
conn.commit()
items = []
创建消费者功能,以使用数据
def consumer(q):
def helper():
while True:
items = [(q.get(),) for _ in range(10000)]
conn.executemany("INSERT INTO table VALUES (?)", items)
conn.commit()
return helper
制作人函数直到无限生成
def producer():
q = Queue()
t = Thread(target=consumer(q))
t.daemon = True
t.start()
for item in InfStream:
q.put(item)
q.task_done()
回复评论的附加说明
如果消费者无法与生产者保持同步
跨越多个消费者 在更快的IO设备中修复数据并稍后将其刷新到数据库。 使计数可配置且动态。
答案 1 :(得分:0)
听起来executemany
在IO上被阻止了,所以threading
在这里可能会有所帮助,所以我会先尝试一下。特别是,创建一个单独的线程,它将简单地调用executemany
第一个线程抛出到共享队列的数据。然后,第一个读取可以继续读取,而第二个线程执行executemany
。正如另一个答案所指出的,这是生产者 - 消费者问题。
如果仍无法解决问题,请切换到multiprocessing
。
请注意,如果您的输入流入的速度比您在第二个线程或进程中写入的速度快,那么这两个解决方案都不会起作用,因为您将比清空内存更快地填充内存。在这种情况下,无论如何,您都必须限制输入读取速率。