Поведение потоков/объединения
Поведение Pysqlites по умолчанию запрещает использование одного соединения в более чем одном потоке. Первоначально он предназначен для работы с более старыми версиями SQLite, которые не поддерживают многопоточные операции при различных обстоятельствах. В частности, старые версии SQLite ни при каких обстоятельствах не позволяли использовать базу данных: memory: database в нескольких потоках.
Pysqlite включает в себя недокументированный флаг, известный как check_same_thread, который отключит эту проверку, однако обратите внимание, что соединения pysqlite по-прежнему небезопасны для одновременного использования в нескольких потоках. В частности, любые вызовы выполнения операторов должны быть внешне мьютексированы, так как Pysqlite не обеспечивает потокобезопасное распространение сообщений об ошибках среди прочего. Таким образом, хотя даже :memory:
базы данных могут совместно использоваться потоками в современном SQLite, Pysqlite не обеспечивает достаточной безопасности потоков, чтобы оправдать это использование.
SQLAlchemy устанавливает пул для работы с поведением Pysqlites по умолчанию:
-
Когда указана база данных :memory:
SQLite, диалект по умолчанию будет использовать SingletonThreadPool
. Этот пул поддерживает одно соединение для каждого потока, так что при любом доступе к модулю в текущем потоке используется одно и то же :memory:
database - другие потоки будут иметь доступ к другому :memory:
database.
-
Когда указана файловая база данных, диалект будет использовать NullPool
в качестве источника соединений. Этот пул закрывает и сбрасывает соединения, которые немедленно возвращаются в пул. Соединения на основе файлов SQLite имеют очень низкую нагрузку, поэтому пул не требуется. Схема также предотвращает повторное использование соединения в другом потоке и лучше всего работает с грубой блокировкой файлов SQLites.
Использование базы данных памяти в нескольких потоках
Чтобы использовать базу данных :memory:
в многопоточном сценарии, один и тот же объект соединения должен быть общим для потоков, поскольку база данных существует только в рамках этого соединения. Реализация StaticPool
будет поддерживать единственное соединение глобально, и флаг check_same_thread
может быть передан Pysqlite как False
:
from sqlalchemy.pool import StaticPool
engine = create_engine('sqlite://',
connect_args={'check_same_thread':False},
poolclass=StaticPool)
Обратите внимание, что для использования базы данных :memory:
в нескольких потоках требуется последняя версия SQLite.