一、自定义线程池
自定义线程池逻辑图
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import threading
import queue
"""
1、写了一个for循环搞300个任务,然后pool.run方法,之后给元祖里面添加任务,满足条件创建一个线程,
紧接着第二个循环又进来了,第一个线程不一定能够执行完毕,然后满足条件再创建一个线程,
接着第三次循环又见来了,这个时候如果前两个线程执行完毕之后,那么为了提高效率,也就不满足判断,就不会
继续创建线程,而是用前两个线程取任务直接执行
2、线程取的任务就是元祖,这里要思考个问题,就是怎么判断任务被取完成了(任务被封存到元祖里面了)
元祖是任务,其他是终止符
3、想要终止 --思路 查看还有多少线程,就增加多少个终止符,然后最后再执行close方法
1)让正在从队列中取任务的线程挂掉
2)主线程,你跳我就跳
4、让当前的任务立即执行,即不管后面还有多少个任务,直接现在线程结束执行
"""
StopEvent = object() #这个是停止标志,但线程执行到队列中这里的时候说明这个停止标志是最后一个,也就是任务执行完毕了
class ThreadPool():
def __init__(self,max_num):
self.q = queue.Queue() #创建一个队列,没有指定参数,说明可以接受无限个东西
self.max_num = max_num #最多创建的线程数(线程池最大容量)
self.generate_list = [] #真实创建的线程列表
self.free_list = [] #空闲的线程数量
self.terminal = False #默认为false的时候不终止
def run(self,func,args,callback=None):
'''
线程池执行一个任务,func要干什么,args参数
'''
w = (func,args,callback,) #封装到元祖里面
self.q.put(w) #把任务封装到队列里面
if len(self.free_list) == 0 and len(self.generate_list) < self.max_num: #如果创建的线程等于0或者小于最大线程数
self.generate_thread()
def generate_thread(self):
'''
创建一个线程
'''
t = threading.Thread(target=self.call) #创建线程调用call方法
t.start()
def call(self):
"""
循环去获取任务函数并执行任务函数
"""
current_thread = threading.current_thread()#获取当前线程
self.generate_list.append(current_thread) #把线程放入到这个列表中
event = self.q.get() #获取任务并且执行
while event !=StopEvent: #如果不是停止标志那么就是任务
#是元祖 ==》任务
#解开任务包
#执行任务
#线程执行任务可能会出错
func,args,callback = event #event就是任务,任务也就是元祖,元祖里面有三个元素
status =True
try:
ret = func(args) #执行func函数,循环里面执行func函数,参数传入就执行任务函数
except Exception as e:
status = False #把标志发给回调函数
ret = e #把错误信息发给回调函数
if callback == None: #设置是否有毁掉函数,有了就传入,没有就不传
pass
else:
callback(status,ret) #把上面函数结果传递给回调函数
if self.terminal: #如果为false就取任务
event = StopEvent
else:
#如果任务全部执行了之后 应该标记:我空闲了
self.free_list.append(current_thread) #任务完成之后把线程添加到空闲任务里面
event = self.q.get()
self.free_list.remove(current_thread) #如果取到任务,那么就把这个线程从空闲列表中移除
else:
#不是元祖,不是任务,这个时候就应该把执行停止标志的线程移除掉
self.generate_list.remove(current_thread)
def close(self):#添加终止符
"""
思路:看结尾还有多少个线程就增加多少个终止符
"""
num = len(self.generate_list)
while num:
self.q.put(StopEvent)
num -=1
def terminate(self): #终止线程,(不清空队列)
self.terminal=True
while self.generate_list:
self.q.put(StopEvent)
self.q.queue.clear()
# #清空队列,先清空队列然后终止线程
# self.q.empty()
# #有可能出现等待的线程,所以要把全部线程终止
# max_num = len(self.genarate_list)
# while max_num:
# self.q.put(StopEvent)
# max_num -=1
import time
def action(i):
time.sleep(0.5)
print(i)
pool = ThreadPool(10)
for item in range(50):#这里的300个就是任务,将任务放置在队列中
"""
开始处理任务
- 创建线程
- 有空闲线程则不再创建线程
- 如果没有空闲线程,就创建线程 ,不能高于线程池的限制
- 根据任务个数判断,如果任务个数低于线程池数,那么就创建任务个数线程,如果高于那么就创建线程池数个线程
- 线程去队列中取任务
"""
pool.run(func=action,args=(item,))
time.sleep(0.1)
pool.terminate()
# time.sleep
# print(len(pool.generate_list))
# pool.close()(2)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
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, arguments, callback = event
try:
result = func(*arguments)
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
full_size = len(self.generate_list)
while full_size:
self.q.put(StopEvent)
full_size -= 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(5)
print(len(pool.generate_list), len(pool.free_list))
print(len(pool.generate_list), len(pool.free_list))
# pool.close()
# pool.terminate()
优化后的代码
二、上下文管理之with自定义open
要用自定义上下文管理必须要用到下面的装饰器
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import contextlib
import queue
@contextlib.contextmanager
def worker_state(xxx,val):
xxx.append(val)
try:
yield 123
finally:
xxx.remove(val)
q = queue.Queue()
q.put("aa")
li = []
with worker_state(li,2) as f:
print(f)
q.get()
View Code
1 """
2 上面执行流程
3 1、先创建队列q
4 2、往队列里面放入值
5 3、往下执行with方法,执行worker_state(li,1): 函数
6 4、执行xxx.append(val),往xxx里面放入值
7 5、执行yield方法,然后执行get方法,从队列里面取值
8 6、最后执行remove方法
9 """
流程说明
执行顺序
扩展:
包含yield 关键字的函数成为一个迭代器,yield跟return的位置一样,只不过每次返回结果后,并没有退出,而是等待下一次迭代,下一次迭代开始后从yield后的语句开始执行,直到再次遇到yield,返回新一次的结果。