详解多线程Django程序耗尽数据库连接的问题


Posted in Python onOctober 08, 2018

Django的ORM是非常好用的,哪怕不是做Web项目也值得一用,所以网上也可以找到不少使用 Django 开发非Web项目的资料,因为除了ORM之个,命令行、配置文件等组件也非常好用。

最近用这种方式开发了一个非Web项目,而且是多线程的。有N个工作线程从DB中获取jobs,并把结果写回DB。简单来说就是这样。

项目运行一段时间后,发现数据库连接耗尽了,幸好内存大,然后一直往上调,最后连接数都上九千多一万了。耗尽连接数的时候,PostgreSQL 会出现类似这样的错误:

FATAL: remaining connection slots are reserved for non-replication superuser connections

然后就各种看文档、代码,找问题,其中艰难略下不表,最后大概是这么些个知识点:

  1. Django里的数据库连接是放在线程的 local() 实例中的。
  2. 任何时候,需要一个数据库连接的话,Django就会创建一条出来,或者用本线程已有的那条。
  3. 如果是Web项目,在请求结束的时候,Django会去关闭掉连接。是的,没有连接池。
  4. 因为我们是非Web项目,所以不存在请求结束事件,所以一直没的关闭连接。但本来这个应该也不会造成问题的,因为没关闭就一直用呗,但不知道哪里出了问题,会出现连接泄漏,所以连接数据会一直增长。

最后的解决方案是找时机主动关闭数据库连接,具体到我们项目,就是每次工作线程完成一个任务后,就把它相关的连接关掉,因为我们用的是 ThreadPoolExecutor ,所以Django很容易做到这一点。

重点代码如下:

from django.db import connections

def on_done(future):
  # 因为每一个线程都有一个 connections,所以这里可以调用 close_all(),把本线程名下的所有连接关闭。
  connections.close_all()

def main():
  # ...
  with ThreadPoolExecutor() as executor:
    while True:
      future = executor.submit(do, get_a_job())
      future.add_done_callback(on_done)

主动关闭后,数据库连接数降到与工作线程数相近,并保持稳定。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python双向链表实现实例代码
Nov 21 Python
Python对小数进行除法运算的正确方法示例
Aug 25 Python
python xml.etree.ElementTree遍历xml所有节点实例详解
Dec 04 Python
Python获取文件所在目录和文件名的方法
Jan 12 Python
Python批量更改文件名的实现方法
Oct 29 Python
python 拷贝特定后缀名文件,并保留原始目录结构的实例
Apr 27 Python
浅析pandas 数据结构中的DataFrame
Oct 12 Python
解决Pytorch训练过程中loss不下降的问题
Jan 02 Python
Python3标准库之functools管理函数的工具详解
Feb 27 Python
python mysql中in参数化说明
Jun 05 Python
Matlab使用Plot函数实现数据动态显示方法总结
Feb 25 Python
opencv实现图像平移效果
Mar 24 Python
JSON文件及Python对JSON文件的读写操作
Oct 07 #Python
Python实现登陆文件验证方法
Oct 06 #Python
python对日志进行处理的实例代码
Oct 06 #Python
浅析Python函数式编程
Oct 06 #Python
Python实现iOS自动化打包详解步骤
Oct 03 #Python
Python中GIL的使用详解
Oct 03 #Python
Python线程同步的实现代码
Oct 03 #Python
You might like
百度站点地图(百度sitemap)生成方法分享
2014/01/09 PHP
PHP冒泡算法详解(递归实现)
2014/11/10 PHP
PHP中应该避免使用同名变量(拆分临时变量)
2015/04/03 PHP
PHP 7的一些引人注目的新特性简单介绍
2015/11/08 PHP
PHP使用stream_context_create()模拟POST/GET请求的方法
2016/04/02 PHP
Laravel框架Eloquent ORM删除数据操作示例
2019/12/03 PHP
PHP实现二维数组(或多维数组)转换成一维数组的常见方法总结
2019/12/04 PHP
PHP 对象继承原理与简单用法示例
2020/04/21 PHP
JQuery 入门实例1
2009/06/25 Javascript
基于jquery实现图片广告轮换效果代码
2011/07/07 Javascript
jQuery仿360导航页图标拖动排序效果代码分享
2015/08/24 Javascript
jQuery leonaScroll 1.1 自定义滚动条插件(推荐)
2016/09/17 Javascript
TypeScript学习之强制类型的转换
2016/12/27 Javascript
详解vue项目构建与实战
2017/06/27 Javascript
jQuery实现上下滚动公告栏详细代码
2018/11/21 jQuery
vue-router传参用法详解
2019/01/19 Javascript
基于vue框架手写一个notify插件实现通知功能的方法
2019/03/31 Javascript
微信小程序bindinput与bindsubmit的区别实例分析
2019/04/17 Javascript
vue简单练习 桌面时钟的实现代码实例
2019/09/19 Javascript
基于JS正则表达式实现模板数据动态渲染(实现思路详解)
2020/03/07 Javascript
vue-cli3 引入 font-awesome的操作
2020/08/11 Javascript
vue 判断页面是首次进入还是再次刷新的实例
2020/11/05 Javascript
Python中使用platform模块获取系统信息的用法教程
2016/07/08 Python
Python数据结构与算法之完全树与最小堆实例
2017/12/13 Python
django manage.py扩展自定义命令方法
2018/05/27 Python
python 字典中文key处理,读取,比较方法
2018/07/06 Python
python中如何实现将数据分成训练集与测试集的方法
2019/09/13 Python
python 实现多线程下载视频的代码
2019/11/15 Python
Python处理PDF与CDF实例
2020/02/26 Python
python rolling regression. 使用 Python 实现滚动回归操作
2020/06/08 Python
Django Admin后台模型列表页面如何添加自定义操作按钮
2020/11/11 Python
白俄罗斯女装和针织品网上商店:Presli.by
2019/10/13 全球购物
学校爱国卫生月活动总结
2014/06/25 职场文书
武侯祠导游词
2015/02/04 职场文书
python基础之函数的定义和调用
2021/10/24 Python
python脚本框架webpy模板赋值实现
2021/11/20 Python