Python探索之自定义实现线程池
作者:带刺的Mary 时间:2021-10-09 08:28:11
为什么需要线程池呢?
设想一下,如果我们使用有任务就开启一个子线程处理,处理完成后,销毁子线程或等得子线程自然死亡,那么如果我们的任务所需时间比较短,但是任务数量比较多,那么更多的时间是花在线程的创建和结束上面,效率肯定就低了。
线程池的原理:
既然是线程池(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()
来源:http://www.cnblogs.com/tangtingmary/p/7729998.html
标签:python,自定义线程池
![](/images/zang.png)
![](/images/jiucuo.png)
猜你喜欢
在python中实现将一张图片剪切成四份的方法
2023-10-04 02:20:04
BluePrint CSS框架0.9版发布
2009-06-03 21:02:00
asp 实现的冒泡排序程序
2011-03-25 11:13:00
并行查询让SQL Server加速运行
2009-03-16 16:31:00
PHP 引用的概念
2023-11-14 21:24:28
详解python的集合set的函数
2023-02-06 04:16:42
![](https://img.aspxhome.com/file/2023/7/103167_0s.png)
关于微信小程序获取小程序码并接受buffer流保存为图片的方法
2023-07-20 09:54:01
Oracle关于时间/日期的操作
2009-02-26 10:37:00
python类中的self和变量用法及说明
2022-05-27 10:33:12
linux中使用boost.python调用c++动态库的方法
2023-01-19 19:21:03
python题解LeetCode303区域和检索示例详解
2022-12-13 16:10:11
python 实时调取摄像头的示例代码
2021-10-17 06:07:52
Python中Parser的超详细用法实例
2022-05-02 10:16:30
Python数据分析之 Pandas Dataframe应用自定义
2023-03-02 09:18:12
![](https://img.aspxhome.com/file/2023/1/97241_0s.png)
使用tf.keras.MaxPooling1D出现错误问题及解决
2021-02-07 05:01:28
![](https://img.aspxhome.com/file/2023/1/99241_0s.png)
ASP Crazy 模版操作类(最简单的模板类、仅提供交流)
2011-03-17 11:06:00
pandas针对excel处理的实现
2022-06-17 07:46:15
![](https://img.aspxhome.com/file/2023/7/87507_0s.jpg)
CSS应用的必要步骤:样式重设
2008-06-11 13:29:00
matplotlib quiver箭图绘制案例
2023-07-13 10:04:11
![](https://img.aspxhome.com/file/2023/3/76893_0s.jpg)
使用Python matplotlib绘制简单的柱形图、折线图和直线图
2022-04-08 02:13:19
![](https://img.aspxhome.com/file/2023/3/97653_0s.png)