侯体宗的博客
  • 首页
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

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

Python  /  管理员 发布于 7年前   164

为什么需要线程池呢?

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

    线程池的原理:

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

    线程池的实现:

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

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

1.low版线程池

设计思路:运用队列queue

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

import queueimport threadingclass 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 queueimport threadingimport contextlibimport timeStopEvent = 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 usepool = ThreadPool(5)def callback(status, result):  # status, execute action status  # result, execute action return value  passdef 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算法之求n个节点不同二叉树个数
    下一条:
    python音频处理用到的操作的示例代码
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 在windows10中升级go版本至1.24后LiteIDE的Ctrl+左击无法跳转问题解决方案(0个评论)
    • 智能合约Solidity学习CryptoZombie第四课:僵尸作战系统(0个评论)
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(95个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客