Python探索之自定义实现线程池


Posted in Python onOctober 27, 2017

为什么需要线程池呢?

        设想一下,如果我们使用有任务就开启一个子线程处理,处理完成后,销毁子线程或等得子线程自然死亡,那么如果我们的任务所需时间比较短,但是任务数量比较多,那么更多的时间是花在线程的创建和结束上面,效率肯定就低了。

    线程池的原理:

        既然是线程池(Thread pool),其实名字很形象,就是把指定数量的可用子线程放进一个"池里",有任务时取出一个线程执行,任务执行完后,并不立即销毁线程,而是放进线程池中,等待接收下一个任务。这样内存和cpu的开销也比较小,并且我们可以控制线程的数量。

    线程池的实现:

        线程池有很多种实现方式,在python中,已经给我们提供了一个很好的实现方式:Queue-队列。因为python中Queue本身就是同步的,所以也就是线程安全的,所以我们可以放心的让多个线程共享一个Queue。

        那么说到线程池,那么理应也得有一个任务池,任务池中存放着待执行的任务,各个线程到任务池中取任务执行,那么用Queue来实现任务池是最好不过的。

1.low版线程池

设计思路:运用队列queue

将线程类名放入队列中,执行一个就拿一个出来

import queue
import threading
class ThreadPool(object):
  def __init__(self, max_num=20):
    self.queue = queue.Queue(max_num) #创建队列,最大数为20
    for i in range(max_num):
      self.queue.put(threading.Thread) #将类名放入队列中
  def get_thread(self):
    return self.queue.get() #从队列中取出类名
  def add_thread(self):
    self.queue.put(threading.Thread) #进类名放入队列中
def func(arg, p): #定义一个函数
  print(arg)
  import time
  time.sleep(2)
  p.add_thread()
pool = ThreadPool(10) #创建对象,并执行该类的构造方法,即将线程的类名放入队列中
for i in range(30):
  thread = pool.get_thread() #调用该对象的get_thread方法,取出类名
  t = thread(target=func, args=(i, pool)) #创建对象,执行func,参数在args中
  t.start()

由于此方法要求使用者修改原函数,并在原函数里传参数,且调用方法也发生了改变,并且有空闲线程浪费资源,实际操作中并不方便,故设计了下一版线程池。

2.绝版线程池

设计思路:运用队列queue

a.队列里面放任务
b.线程一次次去取任务,线程一空闲就去取任务

import queue
import threading
import contextlib
import time
StopEvent = object()
class ThreadPool(object):
  def __init__(self, max_num, max_task_num = None):
    if max_task_num:
      self.q = queue.Queue(max_task_num)
    else:
      self.q = queue.Queue()
    self.max_num = max_num
    self.cancel = False
    self.terminal = False
    self.generate_list = []
    self.free_list = []
  def run(self, func, args, callback=None):
    """
    线程池执行一个任务
    :param func: 任务函数
    :param args: 任务函数所需参数
    :param callback: 任务执行失败或成功后执行的回调函数,回调函数有两个参数1、任务函数执行状态;2、任务函数返回值(默认为None,即:不执行回调函数)
    :return: 如果线程池已经终止,则返回True否则None
    """
    if self.cancel:
      return
    if len(self.free_list) == 0 and len(self.generate_list) < self.max_num:
      self.generate_thread()
    w = (func, args, callback,)
    self.q.put(w)
  def generate_thread(self):
    """
    创建一个线程
    """
    t = threading.Thread(target=self.call)
    t.start()
  def call(self):
    """
    循环去获取任务函数并执行任务函数
    """
    current_thread = threading.currentThread()
    self.generate_list.append(current_thread)
    event = self.q.get()
    while event != StopEvent:
      func, args, callback = event
      try:
        result = func(*args)
        success = True
      except Exception as e:
        success = False
        result = None
      if callback is not None:
        try:
          callback(success, result)
        except Exception as e:
          pass
      with self.worker_state(self.free_list, current_thread):
        if self.terminal:
          event = StopEvent
        else:
          event = self.q.get()
    else:
      self.generate_list.remove(current_thread)
  def close(self):
    """
    执行完所有的任务后,所有线程停止
    """
    self.cancel = True
    count = len(self.generate_list)
    while count:
      self.q.put(StopEvent)
      count -= 1
  def terminate(self):
    """
    无论是否还有任务,终止线程
    """
    self.terminal = True
    while self.generate_list:
      self.q.put(StopEvent)
    self.q.queue.clear()
  @contextlib.contextmanager
  def worker_state(self, state_list, worker_thread):
    """
    用于记录线程中正在等待的线程数
    """
    state_list.append(worker_thread)
    try:
      yield
    finally:
      state_list.remove(worker_thread)
# How to use
pool = ThreadPool(5)
def callback(status, result):
  # status, execute action status
  # result, execute action return value
  pass
def action(i):
  print(i)
for i in range(30):
  ret = pool.run(action, (i,), callback)
time.sleep(3)
print(len(pool.generate_list), len(pool.free_list))
print(len(pool.generate_list), len(pool.free_list))
pool.close()
# pool.terminate()

总结

以上就是本文关于Python探索之自定义实现线程池的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:python中模块的__all__属性详解、Python面向对象编程基础解析(二)等,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

Python 相关文章推荐
Python pygorithm模块用法示例【常见算法测试】
Aug 16 Python
对python3标准库httpclient的使用详解
Dec 18 Python
python颜色随机生成器的实例代码
Jan 10 Python
使用Pycharm在运行过程中,查看每个变量的操作(show variables)
Jun 08 Python
python图片验证码识别最新模块muggle_ocr的示例代码
Jul 03 Python
Python gevent协程切换实现详解
Sep 14 Python
python 下载文件的多种方法汇总
Nov 17 Python
Python下载的11种姿势(小结)
Nov 18 Python
python中封包建立过程实例
Feb 18 Python
基于Python-Pycharm实现的猴子摘桃小游戏(源代码)
Feb 20 Python
Python - 10行代码集2000张美女图
May 23 Python
方法汇总:Python 安装第三方库常用
Apr 26 Python
python音频处理用到的操作的示例代码
Oct 27 #Python
彻底理解Python list切片原理
Oct 27 #Python
Python在不同目录下导入模块的实现方法
Oct 27 #Python
Django视图之ORM数据库查询操作API的实例
Oct 27 #Python
浅谈python函数之作用域(python3.5)
Oct 27 #Python
python+pyqt实现右下角弹出框
Oct 26 #Python
python中模块的__all__属性详解
Oct 26 #Python
You might like
谏山创故乡大分县日田市水坝将设立《进击的巨人》立艾伦、三笠以及阿尔敏的铜像!
2020/03/06 日漫
PHP判断远程图片是否存在的几种方法
2014/05/04 PHP
PHP检测链接是否存在的代码实例分享
2016/05/06 PHP
详解thinkphp中的volist标签
2018/01/15 PHP
一个无限级XML绑定跨框架菜单(For IE)
2007/01/27 Javascript
javascript网页关键字高亮代码
2008/07/30 Javascript
JS 页面自动加载函数(兼容多浏览器)
2009/05/18 Javascript
javascript学习笔记(七)利用javascript来创建和存储cookie
2011/04/08 Javascript
Kibo 用于处理键盘事件的Javascript工具库
2011/10/28 Javascript
window.event快达到全浏览器支持了,以后使用就方便了
2011/11/30 Javascript
js修改table中Td的值(定义td的单击事件)
2013/01/10 Javascript
JQuery DataTable删除行后的页面更新利用Ajax解决
2013/05/17 Javascript
jquery购物车实时结算特效实现思路
2013/09/23 Javascript
浅谈JavaScript 执行环境、作用域及垃圾回收
2016/05/31 Javascript
JS模拟的Map类实现方法
2016/06/17 Javascript
用纯Node.JS弹出Windows系统消息提示框实例(MessageBox)
2017/05/17 Javascript
AugularJS从入门到实践(必看篇)
2017/07/10 Javascript
AngularJS日程表案例详解
2017/08/15 Javascript
antd组件Upload实现自己上传的实现示例
2018/12/18 Javascript
迅速了解一下ES10中Object.fromEntries的用法使用
2019/03/05 Javascript
微信小程序可滑动周日历组件使用详解
2019/10/21 Javascript
extjs图表绘制之条形图实现方法分析
2020/03/06 Javascript
解决element-ui的下拉框有值却无法选中的情况
2020/11/07 Javascript
[08:08]DOTA2-DPC中国联赛2月28日Recap集锦
2021/03/11 DOTA
Python中DJANGO简单测试实例
2015/05/11 Python
Python中使用items()方法返回字典元素对的教程
2015/05/21 Python
python 正则表达式参数替换实例详解
2020/01/17 Python
解决Tensorflow 内存泄露问题
2020/02/05 Python
python使用pymongo与MongoDB基本交互操作示例
2020/04/09 Python
CSS3教程(8):CSS3透明度指南
2009/04/02 HTML / CSS
CSS3实现的文本3D效果附图
2014/09/03 HTML / CSS
HTML5基于flash实现播放RTMP协议视频的示例代码
2020/12/04 HTML / CSS
证婚人经典证婚词
2014/01/09 职场文书
2015会计试用期工作总结
2014/12/12 职场文书
2015少先队大队辅导员工作总结
2015/07/24 职场文书
Python通过loop.run_in_executor执行同步代码 同步变为异步
2022/04/11 Python