详解多线程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 ORM框架SQLAlchemy学习笔记之关系映射实例
Jun 10 Python
简单介绍Python2.x版本中的cmp()方法的使用
May 20 Python
图文讲解选择排序算法的原理及在Python中的实现
May 04 Python
使用Python的Flask框架来搭建第一个Web应用程序
Jun 04 Python
Python利用itchat对微信中好友数据实现简单分析的方法
Nov 21 Python
Centos 升级到python3后pip 无法使用的解决方法
Jun 12 Python
python re正则匹配网页中图片url地址的方法
Dec 20 Python
双向RNN:bidirectional_dynamic_rnn()函数的使用详解
Jan 20 Python
浅谈spring boot 集成 log4j 解决与logback冲突的问题
Feb 20 Python
Python 实现将大图切片成小图,将小图组合成大图的例子
Mar 14 Python
解决keras加入lambda层时shape的问题
Jun 11 Python
Django框架请求生命周期实现原理
Nov 13 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
PHP利用header跳转失效的解决方法
2014/10/24 PHP
thinkPHP框架中执行事务的方法示例
2018/05/31 PHP
那些年,我还在学习jquery 学习笔记
2012/03/05 Javascript
html+js实现动态显示本地时间
2013/09/21 Javascript
详解JavaScript中undefined与null的区别
2014/03/29 Javascript
jQuery动态添加
2016/04/07 Javascript
JavaScript直播评论发弹幕切图功能点集合效果代码
2016/06/26 Javascript
基于JavaScript实现跳转提示页面
2016/09/24 Javascript
html、css和jquery相结合实现简单的进度条效果实例代码
2016/10/24 Javascript
微信小程序  checkbox组件详解及简单实例
2017/01/10 Javascript
原生js实现手风琴功能(支持横纵向调用)
2017/01/13 Javascript
ES6新特性之模块Module用法详解
2017/04/01 Javascript
Vue的Flux框架之Vuex状态管理器
2017/07/30 Javascript
vue2.0 父组件给子组件传递数据的方法
2018/01/15 Javascript
JavaScript日期库date-fn.js使用方法解析
2020/09/09 Javascript
[03:17]DOTA2英雄基础教程 剧毒术士
2013/12/12 DOTA
使用Protocol Buffers的C语言拓展提速Python程序的示例
2015/04/16 Python
详解python中字典的循环遍历的两种方式
2017/02/07 Python
Python基于matplotlib绘制栈式直方图的方法示例
2017/08/09 Python
使用python获取(宜宾市地震信息)地震信息
2019/06/20 Python
python字典的setdefault的巧妙用法
2019/08/07 Python
ubuntu 18.04 安装opencv3.4.5的教程(图解)
2019/11/04 Python
Python 下载及安装详细步骤
2019/11/04 Python
基于Python实现全自动下载抖音视频
2020/11/06 Python
Styleonme中文网:韩国高档人气品牌
2017/06/21 全球购物
Shell如何接收变量输入
2016/08/06 面试题
一道输出判断型Java面试题
2014/10/01 面试题
大学生个人总结的自我评价
2013/10/05 职场文书
一个大学生十年的职业规划
2014/01/17 职场文书
银行青年文明号事迹材料
2014/05/31 职场文书
毕业生爱心捐书倡议书
2015/04/27 职场文书
大学生十八大感想
2015/08/11 职场文书
班主任经验交流心得体会
2015/11/02 职场文书
Go遍历struct,map,slice的实现
2021/06/13 Golang
mysql优化之query_cache_limit参数说明
2021/07/01 MySQL
SpringBoot使用AOP实现统计全局接口访问次数详解
2022/06/16 Java/Android