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

为什么需要线程池呢?

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

    线程池的原理:

        既然是线程池(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()

总结

以上是 Python探索之自定义实现线程池 的全部内容, 来源链接: utcz.com/z/344706.html

回到顶部