带有Django的PyMySQL,多线程应用程序

时间:2017-08-06 19:06:53

标签: django multithreading python-2.7 api pymysql

我们尝试在我们的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(...)

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

我们使用删除功能作为执行删除查询的网关。

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

1 个答案:

答案 0 :(得分:3)

发现问题,

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

  

threadsafety = 1

根据PEP 249

  

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

PyMySQL github问题中的一条评论:

  

每个进程/线程需要一个pysql.connect()。据我所知,这是解决问题的唯一方法。 PyMySQL不是线程安全的,因此不能在多个线程中使用相同的连接。

如果您正在考虑使用其他名为MySQLdb的python包作为您的线程应用程序,请注意MySQLdb消息:

  

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

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