我有兴趣将现有的 Flask“flaskr”教程转换为 Quart 项目。我遇到的一个问题是,当我去注册用于关闭数据库的拆卸方法时,遇到了线程错误
sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread
。有没有办法运行拆卸方法(即路由返回后),以便在同一线程中调用 close() ?
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from sqlite3 import connect
from sqlite3 import PARSE_DECLTYPES
from sqlite3 import Row
from click import command
from click import echo
from quart import current_app
from quart import g
from quart.cli import with_appcontext
def get_db():
"""
Connect to the application's configured database. The connection
is unique for each request and will be reused if this is called
again.
"""
if not hasattr(g, "db"):
g.db = connect(
current_app.config["DATABASE"],
detect_types=PARSE_DECLTYPES,
)
g.db.row_factory = Row
return g.db
def close_db(exception=None):
db = g.pop("db", None)
if db is not None:
db.close()
@command("init-db")
@with_appcontext
def init_db_command() -> None:
db = get_db()
with open(current_app.root_path + "/schema.sql") as file:
db.executescript(file.read())
echo("Initialized the database.")
def init_app(app) -> None:
"""
Register database functions with the Quart app. This is called by
the application factory.
"""
app.teardown_appcontext(close_db)
app.cli.add_command(init_db_command)
return app
运行上述代码命令“init-db”会产生类似于如下所示的错误:
^^^^^^^^^^^^^^^
File "/root/qcv/venv/lib/python3.11/site-packages/quart/cli.py", line 278, in _inner
async with __ctx.ensure_object(ScriptInfo).load_app().app_context():
File "/root/qcv/venv/lib/python3.11/site-packages/quart/ctx.py", line 266, in __aexit__
await self.pop(exc_value)
File "/root/qcv/venv/lib/python3.11/site-packages/quart/ctx.py", line 251, in pop
await self.app.do_teardown_appcontext(exc)
File "/root/qcv/venv/lib/python3.11/site-packages/quart/app.py", line 1169, in do_teardown_appcontext
await self.ensure_async(function)(exc)
File "/root/qcv/venv/lib/python3.11/site-packages/quart/utils.py", line 57, in _wrapper
result = await loop.run_in_executor(
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.11/concurrent/futures/thread.py", line 58, in run
result = self.fn(*self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/root/qcv/qcv/db.py", line 35, in close_db
db.close()
sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 140328473665600 and this is thread id 140328443631296.
仔细查看 Quart 文档后。我认为主要问题是teardown_app 上下文应该调用协程。因此,将 close_db 从同步方法更改为异步方法应该可以修复线程错误。
async def close_db(exception=None):
db = g.pop("db", None)
if db is not None:
db.close()