Понимание Python sqlite механики в многомодульных средах - PullRequest
2 голосов
/ 06 марта 2012

Прежде всего, я понятия не имею, является ли термин "Владение" правильным термином для этого, это просто то, что я называю в 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 существует, потому что Database-Class может вызываться несколькими параллельными потоками, и, хотя сам SQLite является поточно-ориентированным, насколько мне известно, cursor -Object нет) .

Тогда у меня есть рабочий поток, который обрабатывает вещи.

import pyDB
self.DB = pyDB.DB()

class Thread(threading.Thread):
    [omitting some stuff that is not relevant here]
    def doSomethingElse(self, Param):
        DB.doSomething(Param)

Если я выполняю это, я получаю следующее исключение:

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

Теперь, насколько я понимаю, это та же самая проблема, с которой я столкнулся ранее (где владение объектом было дано не инициализированному классу, а тому, который его вызвал. Или я так понимаю это), и это привело меня к окончательному признанию, что я вообще не понимаю, как работает владение объектами в Python Я нашел документацию по Python для понятного объяснения, но не нашел ни одного.

Итак, мои вопросы:

  • Кому принадлежит объект курсора в этом случае? Поток обработки или поток БД?
  • Где я могу прочитать об этом материале, чтобы, наконец, "получить" его?
  • Является ли термин "объект владение " даже правильным, или есть другой термин для этого в Python? (Изменить: Для объяснения этого см. Комментарии к основному вопросу)

Я буду рад получить конкретный совет для этого случая, но, как правило, меня больше интересует вся концепция "что принадлежит кому" в Python, потому что мне кажется, что это довольно сильно отличается от того, как Java это обрабатывает, и так как Я планирую много использовать Python в будущем, я мог бы просто изучить его сейчас, так как это довольно важная часть Python.

Ответы [ 2 ]

4 голосов
/ 06 марта 2012

ProgrammingError: объекты SQLite, созданные в потоке, могут использоваться только в том же

Проблема в том, что вы пытаетесь сохранить курсор по какой-то причине. Вы не должны делать это. Создать новый курсор для каждой транзакции; или, если вы не совсем уверены, где начинаются или заканчиваются транзакции, новый курсор для каждого запроса.

import sqlite3

class DB(object):
    def __init__(self):
        self.conn_uri = './data.sqlite'
        [...]

    def doSomething(self,Param):
        conn = sqlite.connect(self.conn_uri)
        c = conn.cursor()
        c.execute("SELECT * FROM xyz WHERE ID = ?", Param)

Edit, Re comments в вашем вопросе : То, что здесь происходит, имеет мало общего с питоном. Когда вы создаете ресурс sqlite, который является библиотекой C и полностью независим от Python, sqlite требует, чтобы ресурс использовался only в потоке, который его создал. Он проверяет это, просматривая идентификатор потока текущего запущенного потока, и вовсе не пытается координировать передачу ресурса из одного потока в другой. Таким образом, вы обязаны создавать ресурсы sqlite в каждом потоке, который нуждается в них.

В своем коде вы создаете все ресурсы sqlite в методе DB объекта *1014*, который, вероятно, вызывается только один раз, и в основном потоке. Таким образом, эти ресурсы разрешено использовать только в этом потоке, threading.Lock, несмотря на это.

Ваши вопросы:

  • Кому принадлежит объект курсора в этом случае? Поток обработки или поток БД?

Нить, которая его создала. Поскольку, похоже, вы вызываете DB() на уровне модуля, очень вероятно, что это основной поток.

  • Где я могу прочитать об этом материале, чтобы, наконец, "получить" его?

На самом деле нечего получить. За кулисами вообще ничего не происходит, кроме того, что SQLite говорит по этому поводу , когда вы его используете.

  • Является ли термин "владение объектом" даже правильным или есть другой термин для этого в Python?

Python на самом деле не имеет ничего общего с потоками, за исключением того, что он позволяет вам использовать потоки. Вы должны правильно координировать многопоточные приложения.

РЕДАКТИРОВАТЬ снова:

Объекты не живут внутри определенных потоков. Когда вы вызываете метод объекта, этот метод запускается в вызывающем потоке. десять потоков могут вызывать один и тот же метод для одного и того же объекта; все будут работать одновременно (или все, что проходит для этого re GIL), и это зависит от вызывающего или тела метода, чтобы убедиться, что ничего не сломается.

2 голосов
/ 08 марта 2012

Я являюсь автором альтернативной оболочки SQLite для Python (APSW) и хорошо знаком с этой проблемой.Сам SQLite требовал, чтобы объекты - соединение с базой данных и курсоры могли использоваться только в одном потоке.В SQLite 3.5 это было изменено, и вы могли использовать объекты одновременно, хотя внутренне SQLite выполнял свою собственную блокировку, поэтому вы фактически не получали одновременную производительность.Оболочка Python SQLite по умолчанию (она же pysqlite) поддерживает даже старые версии SQLite 3, поэтому она продолжает применять это ограничение, даже если оно больше не требуется для самого SQLite.Однако код pysqlite необходимо изменить, чтобы разрешить параллелизм, поскольку способ, которым он оборачивает SQLite, небезопасен - например, обработка сообщений об ошибках небезопасна из-за недостатков дизайна API SQLite и требует специальной обработки.

Обратите внимание, что курсорыочень дешевый.Не пытайтесь использовать их повторно или относиться к ним как к драгоценным.Фактические базовые объекты SQLite (sqlite3_stmt) хранятся в кеше и используются по мере необходимости.

Если вы хотите максимального параллелизма, откройте несколько соединений и используйте их одновременно.

Документ APSW имеет большеоколо многопоточность и повторный вход .Обратите внимание, что в нем есть дополнительный код, разрешающий фактическое одновременное использование, которого нет в pysqlite, но другие советы и информация применимы к любому использованию SQLite.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...