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 ...
随机推荐
- 实验楼-Git实战教程
实验1-git介绍 1.版本控制系统: 1)集中式版本控制系统:版本库是集中存放在中央服务器的,工作时需要先从中央服务器取得最新的版本,然后工作完成后把自己的修订推送给中央服务器.这类系统都有一个单一 ...
- 完美解决C#Webbrowser控件设置Cookie问题
完美解决C#Webbrowser控件设置Cookie问题由于个人项目需求,需要把从抓包里面的Cookie数据写入到webbrowser空控件里,经过百度白百般折腾,结果还是失败,搜索到的答案基本上都是 ...
- delphi button 实现下拉列表
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...
- 旋转矩阵(Rotation Matrix)的推导及其应用
向量的平移,比较简单. 缩放也较为简单 矩阵如何进行计算呢?之前的文章中有简介一种方法,把行旋转一下,然后与右侧对应相乘.在谷歌图片搜索旋转矩阵时,看到这张动图,觉得表述的很清晰了. 稍微复杂一点的是 ...
- Shader、Draw Call和渲染管线(Rendering Pipeline)
翻阅了很多资料,也做了不少笔记,决定还是对渲染进行一个总结,以巩固所学的东西. <Real-Time Rendering, Third Edition> (PDF的配图链接)将一个渲染 ...
- requirejs整合ztree
{block name='script'} <script> require(['jquery.ztree'], function () { var zTreeObj; var setti ...
- 找回Android studio的帮助文档
对于业余写点小程序,自娱自乐的我来说,写程序过程的帮助文档非常重要,毕竟不是专业人士.用Visual Studio时,习惯于光标一移到一个类或对象上面,马上出现相应的帮助文档(如图) studio的帮 ...
- docker pureftpd
pureftpd: image: vimagick/pure-ftpd ports: - "21:21" volumes: - ./data/ftpuser:/home/ftpus ...
- react diff 原理
(1) 把树形结构按照层级分解,只比较同级元素.(2) 列表结构的每个单元添加唯一的 key 属性,方便比较.(3) React 只会匹配相同 class 的 component(这里面的 class ...
- unit3d 初次接触
最近, 有朋友告我,他们做那个 vr 视频啥的,告我看后,感觉很好,故 ,就去网上搜索一下,了解如下: 1..unit 3d 是啥? Unity3D是一个跨平台的游戏引擎 是由Unity Techno ...