如何继续迭代而不必等待输出完成?

时间:2014-07-11 05:58:51

标签: python sqlite

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秒。

2 个答案:

答案 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()

回复评论的附加说明

  1. 从理论上讲,队列可以扩展到无限大小,受系统资源的限制。
  2. 如果消费者无法与生产者保持同步

    跨越多个消费者    在更快的IO设备中修复数据并稍后将其刷新到数据库。    使计数可配置且动态。

答案 1 :(得分:0)

听起来executemany在IO上被阻止了,所以threading在这里可能会有所帮助,所以我会先尝试一下。特别是,创建一个单独的线程,它将简单地调用executemany第一个线程抛出到共享队列的数据。然后,第一个读取可以继续读取,而第二个线程执行executemany。正如另一个答案所指出的,这是生产者 - 消费者问题。

如果仍无法解决问题,请切换到multiprocessing

请注意,如果您的输入流入的速度比您在第二个线程或进程中写入的速度快,那么这两个解决方案都不会起作用,因为您将比清空内存更快地填充内存。在这种情况下,无论如何,您都必须限制输入读取速率。