提问人:spraff 提问时间:11/16/2023 更新时间:11/16/2023 访问量:24
mysql.connector 应该如何与 Django 应用程序中的线程正确共享?
How should mysql.connector be shared correctly with threads in Django applications?
问:
这涉及到我之前的问题的潜在解决方案,在该问题中,我在将 mysql 游标包装在 和 中得到。commands out of sync; you can't run this command now
__enter__
__exit__
我在其他地方读到过,Django 不会生成新线程来处理多个请求,而是通常会生成多个 Django 进程以实现并行性。尽管有这个建议,我还是开始打印,并注意到它们正在发生变化。Thread.ident
Thread.native_id
基于此,我推测性地写了这样的话:
def db_connect ():
t = threading.current_thread()
if not hasattr (t, 'db_connection'):
print (f"New MyDBConnectionClass for {t.ident}~{t.native_id}")
t.db_connection = MyDBConnectionClass ()
return t.db_connection.get_cursor () # This object has a __exit__ which closes the cursor
以及
class MyDBConnectionClass ():
def __del__(self):
t = threading.current_thread()
print (f"MyDBConnectionClass deleted for {t.ident}~{t.native_id}")
视图处理程序对游标的用法保持不变:
with db_connect() as db:
results = db.all (query, args)
到目前为止,这似乎已经修复了错误(以及原始问题中提到的退出代码 245 崩溃)。commands out of sync
MyDBConnectionClass.__delete__
未被调用,但为几个不同的值创建了各种实例。ident
我目前的假设是,存在某种线程池,并且我的应用程序不可预测地崩溃,因为有时(通常)会在创建初始连接的线程中处理视图,但有时不会。这个实验似乎表明,给每个线程一个不同的连接是有效的,这是有道理的,但我不满意,因为:
- Thread 对象显然没有被删除(或者其他东西被阻止被调用)
MyDBConnection.__del__
- 这与我在其他地方读到的文档和示例不一致
- 它很乱,据我所知,Django 的设计相当干净——我想我一定遗漏了什么
那么,处理mysql连接和游标对象的正确方法是什么,以便我可以这样做
with my_connection_wrapper.get_cursor() as my_cursor_wrapper:
my_cursor_wrapper.foo ()
在 Django 视图中自由地不泄漏资源,也不会导致线程亲和不稳定问题(假设这真的是问题所在)?
答:
你不能在线程之间共享数据库连接,除非你使用一些互斥锁或其他东西来同步线程。即,当一个线程使用 db 连接时,其他线程必须等待。这破坏了运行并行线程的好处。
常见的替代方法是让每个线程打开自己的 db 连接,以便它们各自在各自的 db 连接上都有自己的状态。
MySQL Connector/Python 为此目的提供了连接池。阅读 https://dev.mysql.com/doc/connector-python/en/connector-python-connection-pooling.html
这个想法是,应用程序有一个固定的数据库连接池,每个线程都可以请求从该池“借用”连接。线程执行其查询,然后尽快将连接释放回池,供另一个线程使用。close()
评论
connect()
PoolError
评论