PyMySQL 与 Django,多线程应用程序

Posted

技术标签:

【中文标题】PyMySQL 与 Django,多线程应用程序【英文标题】:PyMySQL with Django, Multithreaded application 【发布时间】:2018-01-14 02:12:17 【问题描述】:

我们正在尝试在我们的 Django (==1.11.4) 环境中使用 Pymysql (==0.7.11)。但是当同时执行多个操作(多个请求发送到同一个 API 函数)时,我们会遇到问题。

我们得到这个错误:

pymysql.err.InternalError: 数据包序列号错误 - 得到 6 预计 1

我们正在尝试从数据库中删除记录(有时大量请求来自多个用户)。

代码:

def delete(self, delete_query):
    self.try_reconnect()
    return self._execute_query(delete_query)

def try_reconnect(self):
    if not self.is_connected:
        self.connection.ping(reconnect=True)

@property
def is_connected(self)
    try:
        self.connection.ping(reconnect=False)
        return True
    execpt:
        return False

def _execute_query(self, query):
    with self.connection.cursor() as cursor:
        cursor.execute(query)
        self.connection.commit()
        last_row_id = cursor.lastrowid
    return last_row_id

我认为没有必要指出这些函数是 DBHandler 类的一部分, 和 self.connection 在 def connect(self) 函数中初始化。

def connect(self):
    self.connection = pymysql.connect(...)

这个connect函数在Django启动时运行一次,我们为整个项目创建一个DBHandler的全局实例(变量),并导入多个文件。

我们使用 delete 函数作为我们的网关来执行删除查询。

我们做错了什么?我们该如何解决?

【问题讨论】:

你还没有说问题出在哪里。还有你为什么直接使用连接,而不是使用Django的orm? 我们正在写入已经存在的数据库(不是我们的)。问题是当我们并行执行操作时会出现异常。异常类型:1. InternalError: 数据包序列号错误 2. AttributeError: 'NoneType' object has no attribute 'timeout' 【参考方案1】:

发现问题,

PyMySQL 是not thread safty 像我们一样共享连接(我们在多个文件之间共享类实例作为全局实例 - 在类中只有一个连接),它被标记为 1:

线程安全 = 1

根据PEP 249:

1 - 线程可以共享模块,但不能共享连接。

PyMySQL github issue 中的 cmets 之一:

每个进程/线程都需要一个 pysql.connect()。据我所知,这是修复它的唯一方法。 PyMySQL 不是线程安全的,因此不能跨多个线程使用同一个连接。

如果您想为线程应用程序使用其他名为 MySQLdb 的 Python 包,请注意 MySQLdb 消息:

不要在线程之间共享连接。这真的不值得你或我的努力,最后可能会损害性能,因为 MySQL 服务器为每个连接运行一个单独的线程。您当然可以做一些事情,例如在池中缓存连接,并一次将这些连接提供给一个线程。如果你让两个线程同时使用一个连接,MySQL 客户端库可能会崩溃并死掉。你被警告了。 对于线程应用程序,请尝试使用连接池。这可以是 使用 Pool 模块完成。

最终我们设法使用了 Django ORM,并且我们只为我们的特定表编写代码,使用 inspectdb 进行管理。

【讨论】:

任何用于多线程mysql的轻量级python库? 你找到了吗? @hunter_tech 我花了 48 小时才找到这篇文章。感谢您的回答。总结:我们向线程发送的对象是什么,请思考以下问题:1。对象会被其他线程共享吗? 2. 如果是,你的对象线程安全吗? 3. 如果不是线程安全的,则发送新对象,如果线程安全则忘记它。 @ArnabMukherjee,我用 golang 代替。 你能详细说明一下吗?你用过 goroutine 吗?

以上是关于PyMySQL 与 Django,多线程应用程序的主要内容,如果未能解决你的问题,请参考以下文章

Django2.X 与 PyMySQL包兼容

Django 与字段和多线程的独特关系

如何使用 pymysql 作为驱动程序配置 Django?

每个Android 都应必须了解的多线程知识点~

什么是 PyMySQL,它与 MySQLdb 有何不同?它会影响 Django 部署吗?

django 多线程 + uWSGI 多线程 遇到的坑