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实现进程间通信简单实例
Jul 23 Python
Python获取邮件地址的方法
Jul 10 Python
Python编程生成随机用户名及密码的方法示例
May 05 Python
Python3正则匹配re.split,re.finditer及re.findall函数用法详解
Jun 11 Python
对pandas处理json数据的方法详解
Feb 08 Python
python Django框架实现web端分页呈现数据
Oct 31 Python
python中的subprocess.Popen()使用详解
Dec 25 Python
python清空命令行方式
Jan 13 Python
python不使用for计算两组、多个矩形两两间的iou方式
Jan 18 Python
Python中itertools的用法详解
Feb 07 Python
解决python对齐错误的方法
Jul 16 Python
python opencv肤色检测的实现示例
Dec 21 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学习笔记 数组遍历实现代码
2011/06/09 PHP
PHP内部实现打乱字符串顺序函数str_shuffle的方法
2019/02/14 PHP
JS setCapture 区域外事件捕捉
2010/03/18 Javascript
JS TextArea字符串长度限制代码集合
2012/10/31 Javascript
Firefox和IE兼容性问题及解决方法总结
2013/10/08 Javascript
jQuery Validate初步体验(二)
2015/12/12 Javascript
很全面的JavaScript常用功能汇总集合
2016/01/22 Javascript
JavaScript将base64图片转换成formData并通过AJAX提交的实现方法
2016/10/24 Javascript
认识less和webstrom的less配置方法
2017/08/02 Javascript
对Vue table 动态表格td可编辑的方法详解
2018/08/28 Javascript
jQuery实现的鼠标拖动浮层功能示例【拖动div等任何标签】
2018/12/29 jQuery
在layui tab控件中载入外部html页面的方法
2019/09/04 Javascript
通过原生vue添加滚动加载更多功能
2019/11/21 Javascript
vue-drag-chart 拖动/缩放图表组件的实例代码
2020/04/10 Javascript
vue+koa2搭建mock数据环境的详细教程
2020/05/18 Javascript
JS指定音频audio在某个时间点进行播放
2020/11/28 Javascript
Python def函数的定义、使用及参数传递实现代码
2014/08/10 Python
Python找出文件中使用率最高的汉字实例详解
2015/06/03 Python
Python cookbook(数据结构与算法)同时对数据做转换和换算处理操作示例
2018/03/23 Python
Python requests发送post请求的一些疑点
2018/05/20 Python
python用列表生成式写嵌套循环的方法
2018/11/08 Python
利用Python实现Excel的文件间的数据匹配功能
2020/06/16 Python
python 基于opencv 绘制图像轮廓
2020/12/11 Python
html5与css3小应用
2013/04/03 HTML / CSS
canvas 基础之图像处理的使用
2020/04/10 HTML / CSS
金属材料工程个人求职的自我评价
2013/12/04 职场文书
物流创业计划书
2014/02/01 职场文书
军神教学反思
2014/02/04 职场文书
手机促销活动方案
2014/02/05 职场文书
培训科主任岗位职责
2014/08/08 职场文书
学习十八大演讲稿
2014/09/15 职场文书
导师对论文的学术评语
2015/01/04 职场文书
小区环境卫生倡议书
2015/04/29 职场文书
2015年医院科室工作总结范文
2015/05/26 职场文书
历史博物馆观后感
2015/06/05 职场文书
Redis数据结构之链表与字典的使用
2021/05/11 Redis