python - 进击的线程池
进击的线程池
简单线程池的设计
一个典型的线程池,应该包括如下几个部分:
1、线程池管理器(ThreadPool),用于启动、停用,管理线程池
2、工作线程(WorkThread),线程池中的线程
3、请求接口(WorkRequest),创建请求对象,以供工作线程调度任务的执行
4、请求队列(RequestQueue),用于存放和提取请求
5、结果队列(ResultQueue),用于存储请求执行后返回的结果
线程池V1--简单线程池
1. 初始化队列,在队列尾部放入类
2. 取出类,执行类(线程任务)
3. 执行完成一个类后,调用初始化,创建新的类,加入队列

class LowThreadPool(): def __init__(self, Q_nums): self.queue = queue.Queue(Q_nums) #创建队列 for i in range(Q_nums): #在队列中添加Q_num个的线程任务 self.queue.put(threading.Thread) #放置线程到队列中 def get_low_thread(self):#获取线程任务 return self.queue.get() def add_low_thread(self):#放置线程任务 self.queue.put(threading.Thread) def func(pool):#任务函数 print("任务开始", pool) print("--------") time.sleep(random.randint(1,3))#随机sleep1-2秒 print("任务结束", pool) time.sleep(0.5) pool.add_low_thread()#把完成任务的线程在加入到线程池中 p = LowThreadPool(5)#线程池中设置5个线程 for i in range(10): ret = p.get_low_thread()#ret = threading.Thread t = ret(target=func, args=(p, )) # t.setDaemon(True) t.start()
线程池V2 -- 加入线程管理功能
V1仅实现利用不停地创建线程去完成队列的任务,并没有循环利用已完成任务的线程重新去队列接收任务。
1. 加入两个容器,
--generate_list = [] 真实的线程列表; --free_list = [] 空闲的线程个数
2. 线程执行管理
将任务放在队列中 queue.put()
着手处理任务 func, args, callback = task,
创建线程:threading.Thread(target = func, args = (xx,))
(限制1,是否有空闲线程,不用创建线程 if free_list=[],
限制2, 没有空闲线程创建线程,线程个数不能超多max_num, generate_list < max
限制3, 根据任务个数创建线程) threading.Thread()
线程去队列中取任务 queue.get()

import threading import queue import time import random StopEvent = object()#设定线程停止对象 class HighThreadPool(): def __init__(self, max_num): self.queue = queue.Queue() #创建队列 self.max_num = max_num #线程最多创建的线程数(线程池的线程最大容量) self.generate_list = []#真实的线程列表,获取线程个数 self.free_list = []#空闲的线程个数, def run(self, func, args, callback=None): tasks = (func, args, callback)#设定任务包 self.queue.put(tasks)#把任务放入队列中 #创建线程的条件1.线程满载,没有空闲的线程执行任务, # 2.线程个数不能超多max_num if len(self.free_list) ==0 and len(self.generate_list) < self.max_num: self.create_thread()#创建一个线程 def create_thread(self): #创建线程 t = threading.Thread(target=self.do_task)#执行task任务 t.start()#开始线程 # 循环获取任务并完成任务, # 当所有任务接近完成时,传入设定的停止StopEvent对象 def do_task(self): #获取当前的线程数量 working_thread = threading.current_thread()#current_thread() => 返回当前线程对象 self.generate_list.append(working_thread)#把线程对象加入列表,获得线程数量 get_task = self.queue.get()#从队列中获取 第一个 任务 while get_task != StopEvent: #若获取元组,表示获取了任务 #获取任务,完成线程任务,获取回调函数, 标记线程空闲,再去取任务 func, args, callback = get_task #获取线程任务的函数,参数,返回值 try:#建立异常,处理func函数错误操作, 回调函数根据正确或错误,作出下一步操作 ret = func(args)#执行函数,获取返回值 flag = True # 异常处理设立标志默认为True except Exception as e: flag = False#出现异常,设为False ret = e #封装错误的信息 pass # callback(flag, ret)#把函数返回值赋值给回调函数, if callback == None:#没有回调函数 try: callback(flag, ret) except Exception as e: pass else: callback(flag, ret)#有返回值,执行回调函数, self.free_list.append(working_thread)#标记线程空闲 get_task = self.queue.get()#执行完上一次函数, 再从队列中获取 第二个 任务 self.free_list.remove(working_thread)#获取新的任务后,从空闲列表去除 else:#若获取StopEvent,表示已经接近完成所有线程任务,把完成任务的线程移除 self.generate_list.remove(working_thread) def working(pool):#任务函数 print("任务开始", pool) print("--------") time.sleep(random.randint(1,3))#随机sleep1-2秒 print("任务结束", pool) time.sleep(0.5) pool.add_low_thread()#把完成任务的线程在加入到线程池中 p = HighThreadPool(10)#线程池中设置10个线程 for i in range(50):#设定50个任务 p.run(func= working, args=(i,))
线程池V3 -- 完成线程的后续
V2实现循环利用线程完成列队的任务,但是在完成所有任务后,线程池中仍有正在等待任务的线程,使得程序无法终止。
1. 设定终止标记StopEvent
2. 在没有新的任务放入队列时,把StopEvent放入队列,当线程获取StopEvent后,线程自动终止。

import threading import queue import time import random StopEvent = object()#设定线程停止对象 class HighThreadPool(): def __init__(self, max_num): self.queue = queue.Queue() #创建队列 self.max_num = max_num #线程最多创建的线程数(线程池的线程最大容量) self.generate_list = []#真实的线程列表,获取线程个数 self.free_list = []#空闲的线程个数, def run(self, func, args, callback=None): tasks = (func, args, callback)#设定任务包 self.queue.put(tasks)#把任务放入队列中 #创建线程的条件1.线程满载,没有空闲的线程执行任务, # 2.线程个数不能超多max_num if len(self.free_list) ==0 and len(self.generate_list) < self.max_num: self.create_thread()#创建一个线程 def create_thread(self): #创建线程 t = threading.Thread(target=self.do_task)#执行task任务 t.start()#开始线程 # 循环获取任务并完成任务, # 当所有任务接近完成时,传入设定的停止StopEvent对象 def do_task(self): #获取当前的线程数量 working_thread = threading.current_thread()#current_thread() => 返回当前线程对象 self.generate_list.append(working_thread)#把线程对象加入列表,获得线程数量 get_task = self.queue.get()#从队列中获取 第一个 任务 while get_task != StopEvent: #若获取元组,表示获取了任务 #获取任务,完成线程任务,获取回调函数, 标记线程空闲,再去取任务 func, args, callback = get_task #获取线程任务的函数,参数,返回值 try:#建立异常,处理func函数错误操作, 回调函数根据正确或错误,作出下一步操作 ret = func(args)#执行函数,获取返回值 flag = True # 异常处理设立标志默认为True except Exception as e: flag = False#出现异常,设为False ret = e #封装错误的信息 pass if callback == None:#没有回调函数 try: callback(flag, ret) except Exception as e: pass else: callback(flag, ret)#有返回值,执行回调函数, self.free_list.append(working_thread)#标记线程空闲 get_task = self.queue.get()#执行完上一次函数, 再从队列中获取 第二个 任务 self.free_list.remove(working_thread)#获取新的任务后,从空闲列表去除 else:#若获取StopEvent,表示已经接近完成所有线程任务,把完成任务的线程移除 self.generate_list.remove(working_thread) #终止线程 #1. 让正在从队列中取任务的线程挂掉 #2. 主线程完成,在队列加上相同数量的StopEvent def close(self):#把StopEvent添加到队列中 thread_num = len(self.generate_list)#从generate_list获取创建线程的个数 while thread_num:#在队列中循环放入topEvent self.queue.put(StopEvent)#队列中加入StopEvent终止线程 thread_num -= 1#线程数减少一个
线程池V4 -- 终止线程任务,清空队列
V3的改善后,已经明显具备模块功能,现在再加入任务被强行终止的功能。
1. 加入terminal_task = False, 默认终止任务为False, 执行终止任务为True
2. 终止线程任务后,queue.empty()清空任务队列
import threading import queue import time import random StopEvent = object()#设定线程停止对象 class HighThreadPool(): def __init__(self, max_num): self.queue = queue.Queue() #创建队列 self.max_num = max_num #线程最多创建的线程数(线程池的线程最大容量) self.terminal_task = False#默认终止任务为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 """ tasks = (func, args, callback)#设定任务包 self.queue.put(tasks)#把任务放入队列中 #创建线程的条件1.线程满载,没有空闲的线程执行任务, # 2.线程个数不能超多max_num if len(self.free_list) ==0 and len(self.generate_list) < self.max_num: self.create_thread()#创建一个线程 def create_thread(self): #创建线程 t = threading.Thread(target=self.do_task)#执行task任务 t.start()#开始线程 # 循环获取任务并完成任务, # 当所有任务接近完成时,传入设定的停止StopEvent对象 def do_task(self): #获取当前的线程数量 working_thread = threading.current_thread()#current_thread() => 返回当前线程对象 self.generate_list.append(working_thread)#把线程对象加入列表,获得线程数量 get_task = self.queue.get()#从队列中获取 第一个 任务 while get_task != StopEvent: #若获取元组,表示获取了任务 #获取任务,完成线程任务,获取回调函数, 标记线程空闲,再去取任务 func, args, callback = get_task #获取线程任务的函数,参数,返回值 try:#建立异常,处理func函数错误操作, 回调函数根据正确或错误,作出下一步操作 ret = func(args)#执行函数,获取返回值 flag = True # 异常处理设立标志默认为True except Exception as e: flag = False#出现异常,设为False ret = e #封装错误的信息 # callback(flag, ret)#把函数返回值赋值给回调函数, if callback == None:#没有回调函数 try: callback(flag, ret) except Exception as e: pass else: callback(flag, ret) # 有返回值,执行回调函数, #若只需完成部分线程,终止其他正在工作的线程, if self.terminal_task:#若出现终止为True get_task = StopEvent else: self.free_list.append(working_thread)#把正在工作的线程加入freelist get_task = self.queue.get() #以获得任务的线程加入StopEvent停止线程任务 self.free_list.remove(working_thread)#移除正在工作的线程 # self.free_list.append(working_thread)#标记线程空闲 # get_task = self.queue.get()#执行完上一次函数, 再从队列中获取 第二个 任务 # self.free_list.remove(working_thread)#获取新的任务后,从空闲列表去除 # else: # self.generate_list.remove(working_thread) # 获取新的任务后,从空闲列表去除 else:#若获取StopEvent,表示已经接近完成所有线程任务,把完成任务的线程移除 self.generate_list.remove(working_thread) #完成所有任务,终止线程 #1. 让正在从队列中取任务的线程挂掉 #2. 主线程完成,在队列加上相同数量的StopEvent def close(self):#把StopEvent添加到队列中 thread_num = len(self.generate_list)#从generate_list获取创建线程的个数 while thread_num:#在队列中循环放入topEvent self.queue.put(StopEvent)#队列中加入StopEvent终止线程 thread_num -= 1#线程数减少一个 def terminate_task(self):#终止线程所有任务,并清空队列 self.terminal_task = True #终止线程所有任务,还存在等待任务线程 while self.generate_list:#循环读取线程列表,若终止任务后存在等待线程 self.queue.put(StopEvent)#加入StopEvent停止线程等待 self.queue.empty() #清空队列任务 # waiting_task_num = len(self.generate_list)#线程任务终止后还存在等待任务线程 # while waiting_task_num: # self.queue.put(StopEvent)#队列加入StopEvent终止 # waiting_task_num -= 1 def working(pool):#任务函数 print("任务开始", pool) print("--------") time.sleep(random.randint(1,3))#随机sleep1-2秒 print("任务结束", pool) time.sleep(0.5) pool.add_low_thread()#把完成任务的线程在加入到线程池中 p = HighThreadPool(5)#线程池中设置10个线程 for i in range(50):#设定50个任务 p.run(func= working, args=(i,)) p.terminate_task()#终止线程任务
V4后,线程池的基本功能已经完成, 线程虽好,但不要贪多。

浙公网安备 33010602011771号