目录
- ThreadPoolExecutor 类
- ProcessPoolExecutor 类
- Future 类
concurrent.futures 模块提供了几种重要的类,通过它们,我们可以方便的创建线程池和进程池并控制他们完成各种操作。下面将会介绍这几种类的用法。
ThreadPoolExecutor 类
ThreadPoolExecutor 是 Executor 的子类(Executor 是 concurrent.futures 模块中定义的一个抽象类),它使用线程池来异步执行调用。
构造方法及各参数含义
class concurrent.futures.ThreadPoolExecutor(max_workers=None, thread_name_prefix='', initializer=None, initargs=())
功能:创建一个最多包含 max_workers 个线程的线程池来异步执行调用
参数:
max_workers: 是一个正整数,表示线程池中线程的数量,3.8 版本的默认值为 min(32, os.cpu_count()+4)
thread_name_prefix: 参数允许用户控制由线程池创建的 threading.Thread 工作线程名称以方便调试
initializer: 表示一个可调用对象,会在每个工作线程开始时调用它
说明:该方法只会在工作线程第一次执行时被调用一次,以后再有新的任务被这个线程执行,该方法也不会再被调用了
initargs 是一个元组,表示传入 initializer 中的位置参数
返回值:一个线程池对象
常用方法及解析
submit(fn, *args, **kwargs)
功能:将任务提交给线程池,以 fn(*args, **kwargs) 的方式执行,并返回 Future 对象代表可调用对象的执行
参数:fn 是一个可调用对象,表示工作线程要执行的任务
*args 和 **kwargs 分别是可调用对象的位置参数列表和关键字参数字典
返回值:一个 Future 对象
map(func, *iterables, timeout=None, chunksize=1)
功能:类似 map() 高级函数,相当于 for + submit()
参数:
func: 表示可调用对象,func 异步执行,且可以并发
*iterables: 表示将被 func 依次作用的参数序列
timeout: 表示阻塞的秒数,可以是 int 或 float,默认为无限制
chunksize: 表示将 iterables 分割的块数,只在进程池中用,线程池中该参数被忽略
返回值:一个等效于 map(func,* iterables)的迭代器
说明:1、使用 ProcessPoolExecutor 时,该方法会将 iterables 分割任务块并作为独立的任务并提交到执行池中。
这些块的大概数量可以由 chunksize 指定正整数设置。 对很长的迭代器来说,使用大的 chunksize 值比默认值 1 能显著地提高性能。
2、如果返回结果的 __next__() 已被调用且返回的结果在对 Executor.map() 的原始调用经过 timeout 秒后还不可用,
则已返回的迭代器将引发 concurrent.futures.TimeoutError
3、如果 func 调用引发一个异常,当从迭代器中取回它的值时这个异常将被引发。
shutdown(wait=True)
功能:关闭线程池(不允许再往线程池中提交任务),并等待线程池中已有的任务执行完毕
参数:wait 表示该方法是否阻塞
返回值:None
说明:如果 wait 为 True 则此方法只有在所有待执行的任务完成执行且释放已分配的资源后才会返回
如果为 False 则该方法立即返回,所有待执行的任务完成执行后会释放已分配的资源
不管 wait 为何值,整个 Python 程序都会等待所有任务完成执行后才退出
代码示例
from concurrent.futures import ThreadPoolExecutor
import threading
import random
import time
def game(id):
th = threading.current_thread()
time.sleep(random.randint(1, 2))
print('任务ID:{}\t线程名:{}'.format(id, th.getName()))
if __name__ == '__main__':
# thread_pool = ThreadPoolExecutor(max_workers=2)
# for i in range(10):
# thread_pool.submit(game, i)
#
# thread_pool.shutdown()
# with ThreadPoolExecutor(max_workers=2) as thread_pool:
# for i in range(10):
# thread_pool.submit(game, i)
with ThreadPoolExecutor(max_workers=2) as thread_pool:
lis = [i for i in range(10)]
thread_pool.map(game, lis)
# 以上三种效果相同
ProcessPoolExecutor 类
ProcessPoolExecutor 和 ThreadPoolExecutor 一样,都是 Executor 的子类,它使用进程池来实现异步执行调用。ProcessPoolExecutor 使用 multiprocessing (它内部导入了该模块)来回避 GIL,但这也意味着它只可以处理和返回可序列化的对象
构造方法及参数解析
class concurrent.futures.ProcessPoolExecutor(max_workers=None, mp_context=None, initializer=None, initargs=())
功能:创建一个进程池对象
参数:
max_workers:表示进程池中的最大进程数,默认为 CPU 个数。不能小于等于0, Windows 上该参数不能大于 61,否则会抛出异常
mp_context:可以是一个多进程上下文或是 None。 它将被用来启动工作进程。 如果 mp_context 为 None 或未给出,将使用默认的多进程上下文
initializer:用于初始化工作进程的可调用对象,与上面介绍的线程池中的一样
initargs:传入initializer 中的位置参数
返回值:一个进程池对象
常用方法及解析
submit()、map()和shutdown()方法,与 ThreadPoolExecutor 一样,请参考上文。
PS:ProcessPoolExecutor 不可以工作在交互式解释器中
示例代码
from concurrent.futures import ProcessPoolExecutor
import os
import random
import time
def game(id):
time.sleep(random.randint(1, 2))
print('任务ID:{}\t进程ID:{}'.format(id, os.getpid()))
if __name__ == '__main__':
with ProcessPoolExecutor(max_workers=3) as process_pool:
for i in range(10):
process_pool.submit(game, i)
Future 类
Future 类是 submit() 方法返回值的类,该类提供了获取线程或进程执行的结果,为线程或进程添加回调函数等方法。它可以将可调用对象封装为异步执行。 该类的实例对象应该由 submit() 方法创建,除非测试,否则不应该直接创建。
常用方法及解析
cancel()
功能:尝试取消调用
参数:无
返回值:如果调用正在执行或已结束运行不能被取消则该方法将返回 False,
否则被取消调用会并且该方法将返回 True
cancelled()
功能:如果取消成功,则返回 True
running()
功能:如果调用正在执行而且不能被取消那么返回 True
done()
功能:如果已被取消或正常结束,则返回 True
result(timeout=None)
功能:获取调用返回(通过 return 返回)的值
参数:timeout 表示阻塞的时间,可以是整数或浮点数。默认无限制
返回值:调用返回的结果
说明:如果设置 timeout 的值,则若阻塞 timeout 秒后仍未执行完成,则引发 concurrent.futures.TimeoutError 异常
exception(timeout=None)
功能:返回调用引发的异常
参数:timeout 表示阻塞的时间,可以是整数或浮点数。默认无限制
返回值:调用引发的异常,若没有异常发生,则返回 None
说明:如果设置 timeout 的值,则若阻塞 timeout 秒后仍未执行完成,则引发 concurrent.futures.TimeoutError 异常
add_done_callback(fn)
功能:回调函数,当线程或进程被取消或完成运行时将会调用 fn ,并把线程或进程的执行结果作为 fn 的唯一参数
参数:fn 是一个可调用对象,有且只能有一个参数,表示回调函数
返回值:None