首先,我不知道“所有权”是否是正确的术语,这正是我在Java中对它的称呼。在
我目前正在构建一个使用SQLite的服务器,遇到了有关对象“所有权”的错误:
我有一个模块来管理SQLite数据库。我们叫它“pyDB”。简化:
import threading
import sqlite3
class DB(object):
def __init__(self):
self.lockDB = threading.Lock()
self.conn = sqlite3.connect('./data.sqlite')
self.c = self.conn.cursor()
[...]
def doSomething(self,Param):
with self.lockDB:
self.c.execute("SELECT * FROM xyz WHERE ID = ?", Param)
(注意,lockDB
对象的存在是因为数据库类可以被多个并发线程调用,尽管SQLite本身是线程安全的,但据我所知,cursor
-对象不是线程安全的)。在
然后我有一个处理东西的工作线程。在
^{pr2}$如果执行此操作,则会出现以下异常:
self.process(task)
File "[removed]/ProcessingThread.py", line 67, in process
DB.doSomething(Param)
File "[removed]/pyDB.py", line 101, in doSomething
self.c.execute(self,"SELECT * FROM xyz WHERE ID = ?", Param)
ProgrammingError: SQLite objects created in a thread can only be used in that same
thread.The object was created in thread id 1073867776 and this is thread id 1106953360
现在,据我所知,这是我遇到的相同问题earlier(对象所有权不是给初始化的类,而是给调用它的类的)。这让我最终接受了这样一个事实:我通常不理解Python中的对象所有权是如何工作的。我已经在Python文档中找到了一个可以理解的解释,但是没有找到任何解释。在
所以,我的问题是:
对于这种情况,我很乐意接受具体的建议,但一般来说,我更感兴趣的是Python中“属于谁的东西”的整个概念,因为对我来说,它似乎与Java处理它的方式非常不同,而且由于我计划在将来大量使用Python,所以我最好现在就学习它,因为这是Python非常重要的一部分。在
问题是由于某种原因,您试图保存光标。你不应该这样做。为每个事务创建一个新的游标;或者,如果您不完全确定事务的开始或结束位置,则为每个查询创建一个新的游标。在
编辑、重新评论您的问题:这里发生的事情与python几乎没有关系。当您创建一个sqlite资源时,它是一个C库,完全独立于python,sqlite要求在创建它的线程中只使用资源。它通过查看当前正在运行的线程的线程ID来验证这一点,而不尝试协调从一个线程到另一个线程的资源传输。因此,您有义务在每个需要它们的线程中创建sqlite资源。在
在代码中,您将在
DB
对象的__init__
方法中创建所有sqlite资源,该方法可能只调用一次,并在主线程中创建。因此,这些资源只允许在该线程中使用,threading.Lock
尽管如此。在您的问题:
创建它的线程。因为它看起来像是在模块级别调用
DB()
,所以它很可能是主线程。在其实没什么好弄的。在幕后什么都没有发生,除了当您使用它时SQLite has to say on the matter什么。在
Python实际上与线程没有太多关系,只是它允许您使用线程。正确地协调多线程应用程序是你的责任。在
再次编辑:
对象不在特定线程内。当您调用对象上的方法时,该方法在调用线程中运行。十个线程可以在同一个对象上调用同一个方法;所有线程都将并发运行(或者传递给GIL的任何线程),并且由调用方或方法体来确保没有中断。在
我是Python(APSW)的替代SQLite包装器的作者,对这个问题非常熟悉。SQLite本身曾经要求对象-数据库连接和游标只能在同一个线程中使用。在SQLite 3.5左右,这一点已经改变了,您可以并发地使用对象,尽管SQLite内部有自己的锁定,所以您实际上并没有获得并发性能。默认的pythonsqlite包装器(aka pysqlite)甚至支持SQLite 3的旧版本,因此它会继续执行此限制,即使SQLite本身不再需要它。但是,pysqlite代码需要修改以允许并发,因为它包装SQLite的方式不安全—例如,处理错误消息是不安全的,因为SQLite API设计缺陷,需要特殊处理。在
注意,光标非常便宜。不要试图重复使用它们或将它们视为珍贵。实际的底层SQLite对象(sqlite3_stmt)保存在缓存中,并根据需要重用。在
如果您想要最大的并发性,那么打开多个连接并同时使用它们。在
APSW文档有更多关于multi-threading and re-entrancy的内容。注意,它有额外的代码来允许pysqlite没有的实际并发使用,但是其他提示和信息适用于SQLite的任何使用。在
相关问题 更多 >
编程相关推荐