简体   繁体   English

在 Python 中序列化 Sqlite3

[英]Serializing Sqlite3 in Python

To fully utilize concurrency, SQLite3 allows threads to access the same connection in three ways:为了充分利用并发性,SQLite3 允许线程以三种方式访问同一个连接:

  1. Single-thread.单线程。 In this mode, all mutexes are disabled and SQLite is unsafe to use in more than a single thread at once.在这种模式下,所有互斥锁都被禁用,并且 SQLite 一次在多个线程中使用是不安全的。
  2. Multi-thread.多线程。 In this mode, SQLite can be safely used by multiple threads provided that no single database connection is used simultaneously in two or more threads.在这种模式下,SQLite 可以被多个线程安全地使用,前提是两个或多个线程中没有同时使用单个数据库连接。
  3. Serialized.序列化。 In serialized mode, SQLite can be safely used by multiple threads with no restriction.在序列化模式下,SQLite 可以不受限制地被多个线程安全使用。

Does anyone know how I can make the connection serialized in Python.有谁知道我如何在 Python 中序列化连接。
Python has "check_same_thread" which allows switching between multi-threading and single-threading; Python 具有“check_same_thread”,允许在多线程和单线程之间切换; however, I can not find out how I should make it serialized.但是,我不知道应该如何将其序列化。

The Python SQLite module is not threadsafe. Python SQLite 模块不是线程安全的。 If you disable its checking then you need to ensure all code is serialized and that includes garbage collection.如果您禁用它的检查,那么您需要确保所有代码都已序列化并且包括垃圾收集。 (My APSW module is threadsafe and also correctly handles the error message thread safety issues). (我的 APSW 模块是线程安全的,也可以正确处理错误消息线程安全问题)。

It is however safe to use multiple independent connections concurrently in the same process and I would recommend you do that.但是,在同一进程中同时使用多个独立连接是安全的,我建议您这样做。 Additionally switch the database into write ahead logging mode and you should get very good performance even with lots of writing.此外,将数据库切换到预写日志记录模式,即使有大量写入,您也应该获得非常好的性能。

I wrote a library to solve this.我写了一个库来解决这个问题。 Works for me.为我工作。

https://github.com/palantir/sqlite3worker https://github.com/palantir/sqlite3worker

The sqlite page http://www.sqlite.org/threadsafe.html says, "The default mode is serialized." sqlite 页面http://www.sqlite.org/threadsafe.ZFC35FDC70D5FC69D269888A说“默认模式是” Have you tested it and found this to not be true?您是否对其进行了测试并发现这不是真的?

Edit:编辑:


If it fails to work, maybe ctypes?如果它无法工作,也许是ctypes? I have no idea if this would have any effect on the loaded sqlite module.我不知道这是否会对加载的 sqlite 模块产生任何影响。 I guess I sort of suspect it doesn't;我想我有点怀疑它没有; as I'd imagine the sqlite3_initialize() function is likely called when the module is loaded?正如我想象的那样,加载模块时可能会调用sqlite3_initialize() function 吗? Or maybe only when you create a database object?或者也许只有当您创建数据库 object 时?

http://www.sqlite.org/c3ref/config.html 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....
>>> 

From Verse Quiz , you might be interested in the __init__ , __serve , and __fetch methods to get you started on creating a serialized SQLite3 database interface in Python.Verse Quiz中,您可能对__init____serve__fetch方法感兴趣,以帮助您开始在 Python 中创建序列化 SQLite3 数据库接口。 Hope that helps you further!希望对您有所帮助!


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]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM