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写的Tkinter程序屏幕居中方法
Mar 10 Python
python自定义类并使用的方法
May 07 Python
python简单实现计算过期时间的方法
Jun 09 Python
使用Python内置的模块与函数进行不同进制的数的转换
Mar 12 Python
浅谈Python使用Bottle来提供一个简单的web服务
Dec 27 Python
使用python对excle和json互相转换的示例
Oct 23 Python
pandas 根据列的值选取所有行的示例
Nov 07 Python
Django forms表单 select下拉框的传值实例
Jul 19 Python
Python实现图片添加文字
Nov 26 Python
python随机数分布random均匀分布实例
Nov 27 Python
如何使用Python抓取网页tag操作
Feb 14 Python
Python中使用threading.Event协调线程的运行详解
May 02 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
php入门学习知识点四 PHP正则表达式基本应用
2011/07/14 PHP
php+js实现图片的上传、裁剪、预览、提交示例
2013/08/27 PHP
PHP伪造来源HTTP_REFERER的方法实例详解
2015/07/06 PHP
PHP使用递归算法无限遍历数组示例
2017/01/13 PHP
使用PHPExcel导出Excel表
2018/09/08 PHP
js调用浏览器打印模块实现点击按钮触发自定义函数
2014/03/21 Javascript
JavaScript中的数组操作介绍
2014/12/30 Javascript
js获取元素外链样式的方法
2015/01/27 Javascript
基于jQuery实现复选框是否选中进行答题提示
2015/12/10 Javascript
基于css3新属性transform及原生js实现鼠标拖动3d立方体旋转
2016/06/12 Javascript
Bootstrap弹出带合法性检查的登录框实例代码【推荐】
2016/06/23 Javascript
Vue.js路由vue-router使用方法详解
2017/03/20 Javascript
nginx配置React静态页面的方法教程
2017/11/03 Javascript
vue文件运行的方法教学
2019/02/12 Javascript
JQuery特殊效果和链式调用操作示例
2019/05/13 jQuery
微信小程序实现带参数的分享功能(两种方法)
2019/05/17 Javascript
[49:17]DOTA2-DPC中国联赛 正赛 Phoenix vs Dynasty BO3 第三场 1月26日
2021/03/11 DOTA
python使用nntp读取新闻组内容的方法
2015/05/08 Python
python 开发的三种运行模式详细介绍
2017/01/18 Python
基于OpenCV python3实现证件照换背景的方法
2019/03/22 Python
Python多线程threading模块用法实例分析
2019/05/22 Python
django页面跳转问题及注意事项
2019/07/18 Python
在django-xadmin中APScheduler的启动初始化实例
2019/11/15 Python
Python3使用腾讯云文字识别(腾讯OCR)提取图片中的文字内容实例详解
2020/02/18 Python
毕业生物理教师求职信
2013/10/17 职场文书
教育学专业毕业生的自我鉴定
2013/11/26 职场文书
建筑行业的大学生自我评价
2013/12/08 职场文书
国旗下的演讲稿
2014/05/08 职场文书
乡镇保密工作责任书
2014/07/28 职场文书
离婚协议书范本2014
2014/10/27 职场文书
劳动仲裁调解书
2015/05/20 职场文书
上诉状格式
2015/05/23 职场文书
2016公司年会主持词
2015/07/01 职场文书
分析ZooKeeper分布式锁的实现
2021/06/30 Java/Android
mysql分表之后如何平滑上线详解
2021/11/01 MySQL
MySQL分区表管理命令汇总
2022/03/21 MySQL