python DBUtils 线程池 连接 Postgresql(多线程公用线程池,DB-API : psycopg2)
一、DBUtils
DBUtils 是一套允许线程化 Python 程序可以安全和有效的访问数据库的模块,DBUtils提供两种外部接口: PersistentDB :提供线程专用的数据库连接,并自动管理连接。 PooledDB :提供线程间可共享的数据库连接,并自动管理连接。
操作数据库模板:
import datetime
import sys
import os
import configparser
import logging
import psycopg2 from DBUtils.PooledDB import PooledDB class DatabaseOperator(object):
'''
class for database operator
''' def __init__(self,
database_config_path, database_config=None):
'''
Constructor
'''
self._database_config_path = database_config_path # load database configuration
if not database_config :
self._database_config = self.parse_postgresql_config(database_config_path)
else:
self._database_config = database_config
self._pool = None def database_config_empty(self):
if self._database_config:
return False
else:
return True def parse_postgresql_config(self, database_config_path=None):
'''解析pei数据库配置文件
参数
---------
arg1 : conf_file
数据库配置文件路径
返回值
--------
dict
解析配置属性dict--config 示例
--------
无
'''
if database_config_path == None and self._database_config_path != None:
database_config_path = self._database_config_path
if not os.path.isfile(database_config_path):
sys.exit("ERROR: Could not find configuration file: {0}".format(database_config_path))
parser = configparser.SafeConfigParser()
parser.read(database_config_path)
config = {}
config['database'] = parser.get('UniMonDB', 'Database')
config['db_user'] = parser.get('UniMonDB', 'UserName')
config['db_passwd'] = parser.get('UniMonDB', 'Password')
config['db_port'] = parser.getint('UniMonDB', 'Port')
config['db_host'] = parser.get('UniMonDB', 'Servername')
self._database_config = config return config def get_pool_conn(self): if not self._pool:
self.init_pgsql_pool()
return self._pool.connection() def init_pgsql_pool(self):
'''利用数据库属性连接数据库
参数
---------
arg1 : config
数据库配置属性
返回值
-------- 示例
--------
无
'''
# 字典config是否为空
config = self.parse_postgresql_config()
POSTGREIP = config['db_host']
POSTGREPORT = config['db_port']
POSTGREDB = config['database']
POSTGREUSER = config['db_user']
POSTGREPASSWD = config['db_passwd']
try:
logging.info('Begin to create {0} postgresql pool on:{1}.\n'.format(POSTGREIP, datetime.datetime.now())) pool = PooledDB(
creator=psycopg2, # 使用链接数据库的模块mincached
maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数
mincached=1, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建
maxcached=4, # 链接池中最多闲置的链接,0和None不限制
blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错
maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制
setsession=[], # 开始会话前执行的命令列表。
host=POSTGREIP,
port=POSTGREPORT,
user=POSTGREUSER,
password=POSTGREPASSWD,
database=POSTGREDB)
self._pool = pool
logging.info('SUCCESS: create postgresql success.\n') except Exception as e:
logging.error('ERROR: create postgresql pool failed:{0}\n')
self.close_db_cursor()
sys.exit('ERROR: create postgresql pool error caused by {0}'.format(str(e))) def pg_select_operator(self, sql):
'''进行查询操作,函数返回前关闭cursor,conn
参数
---------
arg1 : sql查询语句
返回值
--------
list:result
类型为list的查询结果:result 示例
--------
无
'''
# 执行查询
try:
conn = self.get_pool_conn()
cursor = conn.cursor()
cursor.execute(sql)
result = cursor.fetchall()
except Exception as e:
logging.error('ERROR: execute {0} causes error'.format(sql))
sys.exit('ERROR: load data from database error caused {0}'.format(str(e)))
finally:
cursor.close()
conn.close()
return result def test_pool_con(self):
sql = 'select * from tbl_devprofile'
result = self.pg_select_operator(sql)
print(result) def pg_insert_operator(self, sql): result = False
try:
conn = self.get_pool_conn()
cursor = conn.cursor()
cursor.execute(sql)
result = True
except Exception as e:
logging.error('ERROR: execute {0} causes error'.format(sql))
sys.exit('ERROR: insert data from database error caused {0}'.format(str(e)))
finally:
cursor.close()
conn.commit()
conn.close()
return result def pg_update_operator(self, sql): result = False
try:
conn = self.get_pool_conn()
cursor = conn.cursor()
cursor.execute(sql)
result = True
except Exception as e:
logging.error('ERROR: execute {0} causes error'.format(sql))
sys.exit('ERROR: update data from database error caused {0}'.format(str(e)))
finally:
cursor.close()
conn.commit()
conn.close()
return result def pg_delete_operator(self, sql):
result = False
# 执行查询
try:
conn = self.get_pool_conn()
cursor = conn.cursor()
cursor.execute(sql)
result = True
except Exception as e:
logging.error('ERROR: execute {0} causes error'.format(sql))
sys.exit('ERROR: delete data from database error caused {0}'.format(str(e)))
finally:
cursor.close()
conn.commit()
conn.close()
return result def close_pool(self):
'''关闭pool
参数
---------
无 返回值
--------
无
示例
--------
无
'''
if self._pool != None:
self._pool.close() if __name__ == '__main__':
path = "E:\\Users\\Administrator\\eclipse-workspace\\com.leagsoft.basemodule\\base\\config\\sql_conf.conf"
db = DatabaseOperator(
database_config_path=path)
db.test_pool_con()
二、多线程
原理:创建多个线程类,多个线程类共享一个队里Queue,每一个线程类可以操作数据库
from threading import Thread class Worker(Thread):
def __init__(self, queue):
Thread.__init__(self)
self.queue = queue def run(self):
while True:
# Get the work from the queue and expand the tuple
# 从队列中获取任务
database_operator, device, stand_alone_result = self.queue.get()
operateResult(database_operator, device, stand_alone_result)
# 任务执行完之后要通知队列
self.queue.task_done()
填充队列
# 使用队列多线程
logging.info('begin to update all device risk score by multi_processing.\n')
from queue import Queue
queue = Queue()
# 六个线程,每个线程共享一个队列
for _ in range(6):
worker = Worker(queue)
worker.setDaemon(True)
worker.start() for record in all_devid:
device = record[0]
devtype = record[1]
all_countlist = all_dict.get(device)
stand_alone_result = device_assess(all_countlist)
if (devtype in (server_devtype + computer_devtype)) and (stand_alone_result < 100):
stand_alone_result *= 0.8
# 将设备风险评分数据保存到数据库中
queue.put((database_operator, device, stand_alone_result)) #等待队列任务执行完
queue.join() def operateResult(database_operator, device, stand_alone_result):
'''
函数名称: device_assess
描述: 保存单台设备分数到数据库
调用: 无
被调用: main
被访问的表: tbl_devprofile
被修改的表: 无
输入参数: database_operator, device:设备uid, stand_alone_result:单台设备风险分数
输出参数:无
返回值: 单台设备风险分数值
其它: 无
'''
import time
find_profile_sql = "SELECT uiddevrecordid FROM tbl_devprofile WHERE uiddevrecordid='{0}';".format(device)
isExistRecord = database_operator.pg_select_operator(find_profile_sql)
#currentTime=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
currentTime=time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time()))
if len(isExistRecord) > 0:
updata_profile_sql = "UPDATE tbl_devprofile SET irisklevel={0}, dtrisktime='{1}' \
WHERE uiddevrecordid='{2}';".format(stand_alone_result, currentTime, device)
database_operator.pg_update_operator(updata_profile_sql)
else:
insert_profile_sql = "INSERT INTO tbl_devprofile VALUES('{0}',NULL,NULL,NULL,NULL,NULL,NULL,NULL,{1},'{2}');".format(
device, stand_alone_result, currentTime)
database_operator.pg_insert_operator(insert_profile_sql)
使用单线程时,执行完代码花费20s左右,使用多线程时花费5s左右。
Reference:
[1] https://blog.csdn.net/zhaihaifei/article/details/54016939
[2] https://www.cnblogs.com/hao-ming/p/7215050.html?utm_source=itdadao&utm_medium=referral
[3] https://www.cnblogs.com/wozijisun/p/6160065.html (多线程)
[4] http://www.lpfrx.com/archives/4431/
[5] https://www.cnblogs.com/95lyj/p/9047554.html
python DBUtils 线程池 连接 Postgresql(多线程公用线程池,DB-API : psycopg2)的更多相关文章
- Java中线程的使用 (2)-多线程、线程优先级、线程睡眠、让步、阻塞
Java中线程的使用 (2)-多线程.线程优先级.线程睡眠.让步.阻塞 (一)多线程使用方法 说明:创建每个新的线程,一定要记得启动每个新的线程(调用.start()方法) class Xc3 ext ...
- 【死磕线程】线程同步机制_java多线程之线程锁
1.线程各种状态间的切换,用图表示的话简单清晰: 图出处:https://www.cnblogs.com/bhlsheji/p/5099362.html(博主对每个状态解释的清晰明了) 2.为什么需要 ...
- python - DBUtils 连接池减少oracle数据库的连接数
问题: 接到需求,告知项目的oracle连接次数过多,对系统造成太过大的负担,要求减少oracle数据库的连接次数 分析: 仔细分析代码以后,发现产生问题的原因,在于之前要求提升oracle监控的监控 ...
- Python 多线程和线程池
一,前言 进程:是程序,资源集合,进程控制块组成,是最小的资源单位 特点:就对Python而言,可以实现真正的并行效果 缺点:进程切换很容易消耗cpu资源,进程之间的通信相对线程来说比较麻烦 线程:是 ...
- python使用dbutils的PooledDB连接池,操作数据库
1.使用dbutils的PooledDB连接池,操作数据库. 这样就不需要每次执行sql后都关闭数据库连接,频繁的创建连接,消耗时间 2.如果是使用一个连接一直不关闭,多线程下,插入超长字符串到数据库 ...
- python(13)多线程:线程池,threading
python 多进程:多进程 先上代码: pool = threadpool.ThreadPool(10) #建立线程池,控制线程数量为10 reqs = threadpool.makeRequest ...
- python爬虫14 | 就这么说吧,如果你不懂python多线程和线程池,那就去河边摸鱼!
你知道吗? 在我的心里 你是多么的重要 就像 恩 请允许我来一段 freestyle 你们准备好了妹油 你看 这个碗 它又大又圆 就像 这条面 它又长又宽 你们 在这里 看文章 觉得 很开心 就像 我 ...
- python基础-12 多线程queue 线程交互event 线程锁 自定义线程池 进程 进程锁 进程池 进程交互数据资源共享
Python中的进程与线程 学习知识,我们不但要知其然,还是知其所以然.你做到了你就比别人NB. 我们先了解一下什么是进程和线程. 进程与线程的历史 我们都知道计算机是由硬件和软件组成的.硬件中的CP ...
- Python多线程、线程池及实际运用
我们在写python爬虫的过程中,对于大量数据的抓取总是希望能获得更高的速度和效率,但由于网络请求的延迟.IO的限制,单线程的运行总是不能让人满意.因此有了多线程.异步协程等技术. 下面介绍一下pyt ...
随机推荐
- Mac 10.12下安装python3环境
python3感觉用虚拟环境会比较好操作一些,也不用直接卸载python2. 一.基于brew快速安装 # 安装python3 brew install python3 # 安装pip(好像3自带pi ...
- [CentOS7]redis设置开机启动,设置密码
简介 上篇文章介绍了如何安装redis,但每次重启服务器之后redis不会自启,这里将介绍如何进行自启设置,以及如何设置redis的密码,进行密码验证登陆. 上篇文章: Centos7安装Redis ...
- 【小程序】小程序开发自定义组件的步骤>>>>>>>>>小程序开发过程中报错:jsEnginScriptError
报错:jsEnginScriptError VM6342: jsEnginScriptError Component is not found in path "component/spac ...
- Linux之清理linux内存cache
转自:https://www.cnblogs.com/madsnotes/articles/5740495.html 频繁的文件访问会导致系统的Cache使用量大增.例如:在使用grep从很多文件中搜 ...
- gitlab简单使用教程【转】
平时一直是用git来管理代码仓库,也用过一段时间github,但是github免费版不能建私有仓库.后来转到了bitbucket,后来被atlassian收购后有点不适应,而且在国内访问经常连不上.还 ...
- linux go环境安装和基本项目结构
最近项目中要用到Go语言,所以简单总结一下安装和配置,Go这个语言本身就限定了很多规范,比如项目设置,编程风格等,开发中就不需要再因为各种规范问题纠结了,直接用官方规定的能避免很多坑,下面直接切正题, ...
- 分享12款令人瞠目结舌的WebVR演示和实验效果
不管你信不信, WebVR绝对是浏览器下一个让你激动的技术方向, 也许很快你就可以使用VR头显或者相关设备直接访问web内容和资源啦! 在这篇资源分享帖中,我们将介绍很多基于浏览器的VR演示和游戏,帮 ...
- 未能加载文件或程序集“SuperMap.Data.dll”
重新配置的新的开发环境,使用的是原来的工程文件,编译通过,运行报错:"未能加载文件或程序集"SuperMap.Data.dll"或它的某一个依赖项.找不到指定的模块&qu ...
- Docker中部署Mysql5.7和DbAdmin的docker-compose.yml
一.简述 本文讲Docker通过docker-compose.yml部署Mysql5.7和dbAdmin的方法. 二.文件 1.docker-compose.yml内容如下: version: ' s ...
- SpringBoot+SpringDataJPA项目中使用EntityManager执行自定义复杂SQL的方法
import javax.annotation.Resource; import javax.persistence.EntityManager; @Resource private EntityMa ...