【问题标题】:python: how to share an sqlite connection among threads with queues?python:如何在具有队列的线程之间共享sqlite连接?
【发布时间】:2011-07-16 12:04:21
【问题描述】:

我在 Arch Linux x86_64 上使用 Python 3.2.1。
我正在尝试使用类似于以下代码的线程定时循环更新 sqlite 数据库:

import sqlite3
from threading import Timer
from queue import Queue

class DBQueue(Queue):
    def give(self, item):
        self.task_done()
        self.join()
        self.put(item)
        return True


def timer():
    print('A')
    Timer(3, add).start()


def add():
    print('B')
    db = qdb.get()
    cur = db.cursor()
    cur.execute('INSERT INTO Foo (id) VALUES (NULL)')
    qdb.give(db)
    timer()

qdb = DBQueue()
# SOLUTION #1:
# qdb.put(sqlite3.connect(':memory:', check_same_thread=False))
# SOLUTION #2: see Eli Bendersky's answer
qdb.put(sqlite3.connect(':memory:'))
db = qdb.get()
cur = db.cursor()
cur.execute('CREATE TABLE Foo (id INTEGER PRIMARY KEY)')
qdb.give(db)
timer()

不幸返回:

A
B
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python3.2/threading.py", line 736, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.2/threading.py", line 942, in run
    self.function(*self.args, **self.kwargs)
  File "/home/dario/dev/python/prova/src/prova4.py", line 27, in add
    cursor = db.cursor()
sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread.The object was created in thread id 140037302638336 and this is thread id 140037262886656

只共享一个光标并不能提供更好的结果:

conn = sqlite3.connect(':memory:')
qdb.put(conn.cursor())

我很确定我根本不了解如何使用队列在线程之间共享数据库,有人可以帮助我吗? 谢谢!

【问题讨论】:

  • 两分钱:python中不要使用线程,改用多处理,每个进程使用单独的数据库连接。
  • 谢谢,我会看看多处理,但是,另请参阅我在 Eli 的回答中的评论,我想避免多个连接,因为我不想提交更改。这种情况真的不能使用队列吗?
  • 如果我使用check_same_thread=False 连接到数据库,如果我使用队列会很危险吗?
  • 我已经测试了check_same_thread=False 方法,它似乎运行良好:对于那些阅读,请确保避免同时使用排队或类似方法访问数据库。

标签: python multithreading sqlite timer queue


【解决方案1】:

您不需要Queue - 只需使用两个线程到同一个数据库的单独连接即可。请记住,当单独的连接将数据提交到数据库时,您不应该对排序有太多期望。将其视为您有两个不同的程序实例同时访问数据库。


如果出于某种原因你觉得你绝对必须共享一个连接,那么试试这个:既然你遇到了从一个线程创建 SQLite 对象并在另一个线程中使用它们的问题,为什么不委托在单个线程中处理数据库/连接的任务,并让它通过Queues 与其他人通信。更具体地说:

  • 线程 DB_thread:“拥有”连接。从其他线程获取队列中的命令,执行它们,将结果放入“结果队列”
  • 线程 A、B、C:将“命令”传递到队列中并从“结果队列”中获取结果。

请注意,这些命令不是 SQLite 对象。

【讨论】:

  • 谢谢,但是在实际程序中,我使用的是文件数据库,而不是:memory:,并且在明确保存之前我不想提交更改; python文档说“当一个数据库被多个连接访问时,并且其中一个进程修改了数据库,SQLite数据库被锁定,直到该事务被提交”,但是我还是会试一试并在这里报告结果跨度>
  • 就像我记得的那样,如果我使用多个连接,我必须提交更改才能使它们可用于其他连接,我想避免这种情况。 sqlite真的不能用队列吗?否则我将不得不将整个数据库复制到:memory: 或使用临时文件...
  • 酷,我试试看,我从来没有在队列中传递命令,我想我必须将“命令”和“结果”队列都限制为 1 个项目,这样我'我总是确定我检索到了正确的结果。您如何看待我对该问题发表评论的check_same_thread=False 想法?
  • @kynikos:我不熟悉那个选项
  • 哇,经过一番努力,我设法实现了你的想法,而且它似乎运作良好^^ 但是我也测试了check_same_thread 方式,它看起来更干净,甚至更快(对于那些阅读,在这种情况下,一定要实现一种避免同时访问数据库的方法,比如排队)。再次感谢 Eli,您的回答有效,所以我接受了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多