介绍
系統启动了一个新线程的成本是比较高的,因为它涉及到与操作系统的交互。在这种情形下,使用线程池可以很好的提升性能,尤其是当程序中需要创建大量生存期很短暂的线程的时候,更应该考虑使用线程池
线程池在系统启动的时候即创建大量空闲的线程,程序只要将一个函数提交给线程池,线程池就会启动一个空闲的线程来执行它,该线程并不会死亡,而是再次返回到线程池中变为空闲状态,等待执行下一个函数
此外,使用线程池可以有效地控制系统中并发线程的数量。当系统中包含有大量的并发线程时,会导致系统性能急剧下降,甚至导致Python解释器崩溃,而线程池的最大线程参数可以控制系统中并发线程的数量不超过此数
线程池的使用
线程池的基类是concurrent.funtures模块中的Executor,Executor提供了两个子类,即ThreadPoolExecutor和ProcessPoolExecutor,其中ThreadPoolExecutor用于创建线程池,而ProcessPoolExecutor用于创建进程池
如果使用线程池/进程池来管理并发编程,那么只要将相应的task函数提交给线程池/进程池, 剩下的事情就由线程池/进程池来解决
Executor提供了如下常用方法:
submit(fn, *args, **kwargs): 将fn函数提交给线程池,*args代表传给fn函数的参数,*kwargs代表以关键字参数的形式为fn函数传入参数
map(func, *iterables, timeout=None, chunksize=1): 该函数类似于全局函数map(func, *iterables), 只是该函数将会启动多个线程,以异步方式立即对iterables执行map处理
shutdown(wait=True): 关闭线程池
程序将task函数提交(submit)给线程池后,submit方法会返回一个Future对象,Future类主要获取线程任务函数的返回值。由于线程任务会在新线程中以异步方式执行,因此,线程执行的函数相当于一个将来完成的任务,所以Python使用Future来代表
Future提供了如下方法:
cancel(): 取消该Future代表的线程任务。如果该任务正在执行,不可取消,则该方法返回False;否则,程序会取消该任务,并返回True
cancelled(): 返回Future代表的线程任务是否被成功取消
running(): 如果该Future代表的线程任务正在执行,不可被取消,该方法返回True
done(): 如果该Future代表的线程任务被成功取消或执行完成,则该方法返回True
result(timeout=None): 获取该Future代表的线程任务最后返回的结果。如果Future代表的线程任务还未完成,该方法将会阻塞当前进程,其中timeout参数指定最后阻塞多少秒
execption(timeout=None): 获取该Future代表的线程任务所引发的异常。如果该任务成功完成,没有异常,则该方法返回None
add_done_callback(fn): 为该Funture代表的线程任务注册一个回调函数,当该任务成功完成时,程序自动触发该fn函数
在用完一个线程池后,应该调用线程池的shutdonw()方法,该方法将启动线程池的关闭序列。调用shutdown()方法后的线程池不再接受新任务,但会将以前所有已提交的任务执行完成。当线程池中的所有任务都执行完后,改线程池中的所有线程都会死亡
实例:
# 线程池 from concurrent.futures import ThreadPoolExecutor import threading import time # 定义一个准备作为线程任务的函数 def action(max): mysum = 0 for i in range(max): mysum += i print(threading.current_thread().name + ' ' + str(i)) return mysum # 创建一个包含2条线程的线程池 with ThreadPoolExecutor(max_workers=2) as pool: # 向线程池提交一个task, 50会作为action()函数的参数 future1 = pool.submit(action, 10) # 向线程池再提交一个task, 100会作为action()函数的参数 future2 = pool.submit(action, 5) def get_result(future): print(future.result()) # 为future1添加线程完成的回调函数 future1.add_done_callback(get_result) # 为future2添加线程完成的回调函数 future2.add_done_callback(get_result) print('-------end-------')