Python线程池简单实现
线程池介绍
“这些都是假设,不能充分说明问题,下面我将讨论线程池的简单实现并对该程序进行对比测试,以说明线程技术优点及应用领域。”
假设过后一定要验证,单纯开脑洞没有意义…
简单地说,“池化资源”技术就是用空间换时间,事先分配好资源,用的时候直接用,程序结束时释放资源,这样在使用资源时便可省去分配和释放的时间,最终实现性能的提升。
tips:
这种“事先分配N个资源,供之后M次调用”的方案,除提升性能外,还有以下好处:
1、N < M时,可实现复用,避免资源消耗过大。比如在一个socket上模拟多个socket通信,真实socket实现包的分发。这样可以避免多socket通信带来过大的资源消耗。
2、N > M时,可实现冗余。
3、将资源分配与资源使用解耦。
-
文档中给出的线程池架构如下:
-
一般一个简单线程池至少包含下列组成部分。
- 线程池管理器(ThreadPoolManager):用于创建并管理线程池
- 工作线程(WorkThread): 线程池中线程
- 任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行。
- 任务队列:用于存放没有处理的任务。提供一种缓冲机制。
-
线程池管理器至少有下列功能:创建线程池,销毁线程池,添加新任务
上图为一个最原始的线程池架构图。用户使用线程池管理器提供的接口添加任务。线程池管理线程和工作线程使用任务队列传递任务信息(调用的函数、参数)。
类似于C中的main函数,在调用main函数前需要做一些初始化工作,对应的,main函数结束后需要做一些清理工作。C的做法是先调用CRTStartup系列函数,在该函数中调用main函数。工作线程执行任务时可使用类似的做法,与CRTStartup系列函数对应的便是任务接口。最简单的任务接口,只需要不断查询任务队列即可。
Python实现
以下是用Python简单实现的线程池
import threading
import queue
class Work_Thread(threading.Thread):
"""工作线程类
"""
def __init__(self, work_queue):
"""工作线程类初始化函数
"""
threading.Thread.__init__(self)
self._work_queue = work_queue #线程同步队列
self.setDaemon(True) #主线程退出后,子线程也退出
self.start()
def run(self):
"""任务接口
"""
while True:
try:
func, args = self._work_queue.get()
func(args)
self._work_queue.task_done()
except Exception as reason:
print(reason)
break
class Thread_Pool(object):
"""线程池管理类
"""
def __init__(self, thread_count = 1):
"""线程池管理器初始化函数
Args:
thread_count: 线程池中的线程个数
"""
self._thread_count = thread_count
self._work_queue = queue.Queue()
self._threads = []
self.init_threads_pool()
def init_threads_pool(self):
"""建立并启动thread_count个线程
"""
for index in range(self._thread_count):
self._threads.append(Work_Thread(self._work_queue))
def add_work(self, function, param):
"""增加新任务。 (调用函数,参数)
"""
self._work_queue.put((function, param))
def wait_queue_empty(self):
"""等待队列为空。某些场景下可等同于所有任务均执行完
"""
self._work_queue.join()
def work_func(num):
"""测试函数,在控制台打印num
"""
print(num)
def main():
"""Thread_Pool使用例子
"""
thread_count = 5
thread_pool = Thread_Pool(thread_count)
for num in range(0, 100):
thread_pool.add_work(work_func, num) #添加任务
thread_pool.wait_queue_empty() #等待任务执行完
print("---end---")
if __name__ == "__main__":
main()
Tips
除了提升性能,线程池可以减少启动线程的代码。
以Python为例,启动线程需要创建线程对象并调用start()
方法。若使用线程池,则只需调用add_work()
方法。
欢迎讨论:)如有错误还望留言指正。