Python 使用threading+Queue实现线程池示例


Posted in Python onDecember 21, 2019

一、线程池

1、为什么需要使用线程池

1.1 创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率。

记创建线程消耗时间T1,执行任务消耗时间T2,销毁线程消耗时间T3,如果T1+T3>T2,那说明开启一个线程来执行这个任务太不划算了!在线程池缓存线程可用已有的闲置线程来执行新任务,避免了创建/销毁带来的系统开销。

1.2 线程并发数量过多,抢占系统资源从而导致阻塞。

线程能共享系统资源,如果同时执行的线程过多,就有可能导致系统资源不足而产生阻塞的情况。

1.3 对线程进行一些简单的管理。

比如:延时执行、定时循环执行的策略等,运用线程池都能进行很好的实现。

2、Python中建立线程池的方法

2.1 使用threadpool模块,这是个python的第三方模块,支持python2和python3

2.2 使用concurrent.futures模块,这个模块是python3中自带的模块,python2.7以上版本也可以安装使用

2.3 自己构建一个线程池

二、队列(queue)

Queue模块提供的队列(FIFO)适用于多线程编程,在生产者(producer)和消费者(consumer)之间线程安全(thread-safe)地传递消息或其它数据,因此多个线程可以共用同一个Queue实例。常用方法:

Queue.qsize():返回queue的大小。

Queue.empty():判断队列是否为空,通常不太靠谱。

Queue.full():判断是否满了。

Queue.put(item, block=True, timeout=None): 往队列里放数据。

Queue.put_nowait(item):往队列里存放元素,不等待

Queue.get(item, block=True, timeout=None): 从队列里取数据。

Queue.get_nowait(item):从队列里取元素,不等待

Queue.task_done():表示队列中某个元素是否的使用情况,使用结束会发送信息。

Queue.join():一直阻塞直到队列中的所有元素都执行完毕。

三、使用threading+Queue处理多任务

假设有十个任务需要处理,打算在后台开启五个线程,简化后的模型

import Queue
import threading
import time
 
queue = Queue.Queue()
 
class ThreadNum(threading.Thread):
  def __init__(self, queue):
    threading.Thread.__init__(self)
    self.queue = queue
 
  def run(self):
    while True:
      #消费者端,从队列中获取num
      num = self.queue.get()
      print("Retrieved", num)
      time.sleep(1) 
      #在完成这项工作之后,使用 queue.task_done() 函数向任务已经完成的队列发送一个信号
      self.queue.task_done()
    
    print("Consumer Finished")
 
def main():
  #产生一个 threads pool, 并把消息传递给thread函数进行处理,这里开启10个并发
  for i in range(5):
    t = ThreadNum(queue)
    t.setDaemon(True)
    t.start()
  
  #往队列中填数据 
  for num in range(10):
    queue.put(num)
    #wait on the queue until everything has been processed
  
  queue.join()
   
if __name__ == '__main__':
  main()
  time.sleep(500)

输出为:

('Retrieved', 0)
 ('Retrieved', 1)('Retrieved', 2)
('Retrieved', 3)
('Retrieved', 4)
('Retrieved', 5)('Retrieved', 6)
('Retrieved', 7)
('Retrieved', 8)
 ('Retrieved', 9)

具体工作步骤描述如下:

1、创建一个 Queue.Queue() 的实例,然后使用数据对它进行填充。

2、将经过填充数据的实例传递给线程类,后者是通过继承 threading.Thread 的方式创建的。

3、生成守护线程池。

4、每次从队列中取出一个项目,并使用该线程中的数据和 run 方法以执行相应的工作。

5、在完成这项工作之后,使用 queue.task_done() 函数向任务已经完成的队列发送一个信号。

6、对队列执行 join 操作,实际上意味着等到队列为空,再退出主程序。

在使用这个模式时需要注意一点:通过将守护线程设置为 true,程序运行完自动退出。好处是在退出之前,可以对队列执行 join 操作、或者等到队列为空。

注意运行main函数后继续执行time.sleep(500),可以观察到主线程未结束的情况下ThreadNum(queue)生成的线程还在运行。如果需要停止线程的话可以对以上代码加以修改。

import Queue
import threading
import time
 
queue = Queue.Queue()
 
class ThreadNum(threading.Thread):
  """没打印一个数字等待1秒,并发打印10个数字需要多少秒?"""
  def __init__(self, queue):
    threading.Thread.__init__(self)
    self.queue = queue
 
  def run(self):
    done = False
    while not done:
      #消费者端,从队列中获取num
      num = self.queue.get()
      if num is None:
        done = True
      else:
        print("Retrieved", num)
      time.sleep(1) 
      #在完成这项工作之后,使用 queue.task_done() 函数向任务已经完成的队列发送一个信号
      self.queue.task_done()
    
    print("Consumer Finished")
def main():
  #产生一个 threads pool, 并把消息传递给thread函数进行处理,这里开启10个并发
  for i in range(5):
    t = ThreadNum(queue)
    t.setDaemon(True)
    t.start()
  
  #往队列中填错数据 
  for num in range(10):
    queue.put(num)
  
  queue.join()
  time.sleep(100)
  for i in range(10):
    queue.put(None)
    print('None')
  time.sleep(200)
   
if __name__ == '__main__':
  start = time.time()
  main()
  print"Elapsed Time: %s" % (time.time() - start)

main函数执行完后队列向线程发送None消息,触发线程的停止标识,这样就可以动态管理线程池了。

以上这篇Python 使用threading+Queue实现线程池示例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python去掉字符串中重复字符的方法
Feb 27 Python
Python实现控制台输入密码的方法
May 29 Python
python字符串str和字节数组相互转化方法
Mar 18 Python
python获取多线程及子线程的返回值
Nov 15 Python
微信小程序跳一跳游戏 python脚本跳一跳刷高分技巧
Jan 04 Python
pandas dataframe添加表格框线输出的方法
Feb 08 Python
Python 获取项目根路径的代码
Sep 27 Python
Python多继承以及MRO顺序的使用
Nov 11 Python
Python3.9 beta2版本发布了,看看这7个新的PEP都是什么
Jun 10 Python
用pandas划分数据集实现训练集和测试集
Jul 20 Python
Django显示可视化图表的实践
May 10 Python
用Python创建简易网站图文教程
Jun 11 Python
Python CSV文件模块的使用案例分析
Dec 21 #Python
python实现的分析并统计nginx日志数据功能示例
Dec 21 #Python
Python数据持久化存储实现方法分析
Dec 21 #Python
python cv2截取不规则区域图片实例
Dec 21 #Python
Python lxml模块的基本使用方法分析
Dec 21 #Python
python Manager 之dict KeyError问题的解决
Dec 21 #Python
tornado+celery的简单使用详解
Dec 21 #Python
You might like
浅谈电磁辐射对健康的影响
2021/03/01 无线电
smtp邮件发送一例
2006/10/09 PHP
phpmyadmin 常用选项设置详解版
2010/03/07 PHP
ThinkPHP模板中判断volist循环的最后一条记录的验证方法
2014/07/01 PHP
在b/s开发中经常用到的javaScript技术
2006/08/23 Javascript
比较简单实用的使用正则三种版本的js去空格处理方法
2007/11/18 Javascript
jQuery事件 delegate()使用方法介绍
2012/10/30 Javascript
JS获取iframe中marginHeight和marginWidth属性的方法
2015/04/01 Javascript
省市区三级联动下拉框菜单javascript版
2015/08/11 Javascript
jQuery针对input的class属性写了多个值情况下的选择方法
2016/06/03 Javascript
原生 JS Ajax,GET和POST 请求实例代码
2016/06/08 Javascript
基于Turn.js 实现翻书效果实例解析
2016/06/20 Javascript
基于Bootstrap实现下拉菜单项和表单导航条(两个菜单项,一个下拉菜单和登录表单导航条)
2016/07/22 Javascript
Nodejs实现短信验证码功能
2017/02/09 NodeJs
SVG描边动画
2017/02/23 Javascript
基于AGS JS开发自定义贴图图层
2017/03/31 Javascript
Centos6.8下Node.js安装教程
2017/05/12 Javascript
Vue中建立全局引用或者全局命令的方法
2017/08/21 Javascript
vue-router路由模式详解(小结)
2019/08/26 Javascript
three.js 制作动态二维码的示例代码
2020/07/31 Javascript
[37:47]IG vs Winstrike 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
Python pickle类库介绍(对象序列化和反序列化)
2014/11/21 Python
python opencv 图像尺寸变换方法
2018/04/02 Python
python3使用QQ邮箱发送邮件
2020/05/20 Python
python如何爬取网站数据并进行数据可视化
2019/07/08 Python
python实现将文件夹内的每张图片批量分割成多张
2019/07/22 Python
如何基于Python获取图片的物理尺寸
2019/11/25 Python
jupyter 实现notebook中显示完整的行和列
2020/04/09 Python
前后端结合实现amazeUI分页效果
2020/08/21 HTML / CSS
挪威户外活动服装和装备购物网站:Bergfreunde挪威
2016/10/20 全球购物
Linux如何修改文件和文件夹的权限
2012/06/27 面试题
幼儿园师德师风心得体会
2016/01/12 职场文书
市直属机关2016年主题党日活动总结
2016/04/05 职场文书
JavaScript嵌入百度地图API的最详细方法
2021/04/16 Javascript
总结Python常用的魔法方法
2021/05/25 Python
Mysql 如何合理地统计一个数据库里的所有表的数据量
2022/04/18 MySQL