Сериализация Sqlite3 в Python - PullRequest
18 голосов
/ 09 июня 2011

Для полного использования параллелизма SQLite3 позволяет потокам получать доступ к одному и тому же соединению тремя способами:

  1. Single-нить. В этом режиме все мьютексы отключены, и SQLite небезопасно использовать более чем в одном потоке одновременно.
  2. Multi-нить. В этом режиме SQLite может безопасно использоваться несколькими потоками при условии, что ни одно соединение с базой данных не используется одновременно в двух или более потоках.
  3. Сериализированные. В сериализованном режиме SQLite может безопасно использоваться несколькими потоками без ограничений.

Кто-нибудь знает, как я могу сделать сериализованное в Python соединение.
Python имеет "check_same_thread", который позволяет переключаться между многопоточностью и однопоточностью; однако, я не могу узнать, как я должен сделать это сериализованным.

Ответы [ 4 ]

6 голосов
/ 11 июня 2011

Модуль Python SQLite не является потокобезопасным.Если вы отключите его проверку, вам нужно убедиться, что весь код сериализован и включает сборку мусора.(Мой модуль APSW является поточно-ориентированным и корректно обрабатывает сообщения об ошибках безопасности потока).

Однако безопасно одновременно использовать несколько независимых соединений в одном процессе, и я бы порекомендовал вам сделать это.Дополнительно переключите базу данных в режим записи с опережением записи , и вы получите очень хорошую производительность даже при большом количестве записей.

2 голосов
/ 24 ноября 2015

Я написал библиотеку, чтобы решить эту проблему. У меня работает.

https://github.com/palantir/sqlite3worker

1 голос
/ 09 июня 2011

Страница sqlite http://www.sqlite.org/threadsafe.html говорит: «Режим по умолчанию сериализуется». Вы проверили это и обнаружили, что это не соответствует действительности?

Edit:


Если это не сработает, может быть, ctypes? Я понятия не имею, повлияет ли это на загруженный модуль sqlite. Я полагаю, что вроде как нет; как я себе представляю, функция sqlite3_initialize(), вероятно, вызывается при загрузке модуля? Или, может быть, только когда вы создаете объект базы данных?

http://www.sqlite.org/c3ref/config.html

>>> import sqlite3
>>> import ctypes
>>> from ctypes.util import find_library
>>> sqlite_lib = ctypes.CDLL(find_library('sqlite3'))
>>> sqlite_lib.sqlite3_config(3) # http://www.sqlite.org/c3ref/c_abort.html
0   # no error....
>>> 
0 голосов
/ 09 июня 2011

Из Verse Quiz , вас могут заинтересовать методы __init__, __serve и __fetch, с которых можно начать создание сериализованного интерфейса базы данных SQLite3 в Python.Надеюсь, что это поможет вам в дальнейшем!


import _thread
import sqlite3
import queue

################################################################################

class Server:

    """Execute a protected SQLite3 database on a singular thread.

    Since a SQLite3 database can only accept queries on the thread that it
    was created on, this server receives requests through a queue and sends
    back the result through a list and mutex mechanism."""

    def __init__(self, *args):
        """Initialize the Server with a SQLite3 database thread."""
        self.__lock = _thread.allocate_lock()
        self.__lock.acquire()
        _thread.start_new_thread(self.__serve, args)
        self.__lock.acquire()
        del self.__lock
        if self.__error is not None:
            raise self.__error
        del self.__error

    def __serve(self, *args):
        """Run a server continuously to answer SQL queries.

        A SQLite3 connection is made in this thread with errors being raised
        again for the instantiator. If the connection was made successfully,
        then the server goes into a continuous loop, processing SQL queries."""
        try:
            database = sqlite3.connect(*args)
        except:
            self.__error = error = sys.exc_info()[1]
        else:
            self.__error = error = None
        self.__lock.release()
        if error is None:
            self.__QU = queue.Queue()
            while True:
                lock, one, sql, parameters, ret = self.__QU.get()
                try:
                    cursor = database.cursor()
                    cursor.execute(sql, parameters)
                    data = cursor.fetchone() if one else cursor.fetchall()
                    ret.extend([True, data])
                except:
                    ret.extend([False, sys.exc_info()[1]])
                lock.release()

    def fetch(self, one, sql, *parameters):
        """Execute the specified SQL query and return the results.

        This is a powerful shortcut method that is the closest connection
        other threads will have with the SQL server. The parameters for the
        query are dumped into a queue, and the answer is retrieved when it
        becomes available. This prevents SQLite3 from throwing exceptions."""
        lock, ret = _thread.allocate_lock(), []
        lock.acquire()
        self.__QU.put((lock, one, sql, parameters, ret))
        lock.acquire()
        if ret[0]:
            return ret[1]
        raise ret[1]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...