从Python3.2开始,标准库为我们提供了concurrent.futures模块,它提供了ThreadPoolExecutor和ProcessPoolExecutor两个类,实现了对threading和multiprocessing的进一步抽象,对编写线程池/进程池提供了直接的支持。

1. 进程池

1.1 concurrent.futures.ProcessPoolExecutor()
1.1.1 ProcessPoolExectuor 提供了如下常用方法:
  • 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 来代表。

1.1.2 Future 提供了如下方法:
  • cancel():取消该 Future 代表的线程任务。如果该任务正在执行,不可取消,则该方法返回 False;否则,程序会取消该任务,并返回 True。
  • cancelled():返回 Future 代表的线程任务是否被成功取消。
  • running():如果该 Future 代表的线程任务正在执行、不可被取消,该方法返回 True。
  • done():如果该 Funture 代表的线程任务被成功取消或执行完成,则该方法返回 True。
  • result(timeout=None):获取该 Future 代表的线程任务最后返回的结果。如果 Future 代表的线程任务还未完成,该方法将会阻塞当前线程,其中 timeout 参数指定最多阻塞多少秒。
  • exception(timeout=None):获取该 Future 代表的线程任务所引发的异常。如果该任务成功完成,没有异常,则该方法返回 None。
  • add_done_callback(fn):为该 Future 代表的线程任务注册一个“回调函数”,当该任务成功完成时,程序会自动触发该 fn 函数。

  在用完一个线程池后,应该调用该线程池的 shutdown() 方法,该方法将启动线程池的关闭序列。调用 shutdown() 方法后的线程池不再接收新任务,但会将以前所有的已提交任务执行完成。当线程池中的所有任务都执行完成后,该线程池中的所有线程都会死亡。

1.1.3 concurrent.futures.wait(fs, timeout=None, return_when=ALL_COMPLETED)

  返回两个二元组集合,第一个集合名为done,包含已经完成的futures;第二个集合名为not_done,包含没有完成的futures。return_when参数指明了这个方法什么时候返回,一共有三种参数,默认为ALL_COMPLETED。

1. FIRST_COMPLETED:当任何future完成或被取消时返回
2. FIRST_EXCEPTION:当任何future引起一个异常时返回,如果没有异常,等效于ALL_COMPLETED
3. ALL_COMPLETED:当所有futures完成或被取消时返回
1.1.4 concurrent.futures.as_completed(fs, timeout=None)

  返回由fs给出的Future实例迭代器,只有当future完成时才会返回,返回的顺序与完成的顺序相同,最先完成的最先返回,如果fs中包含两个同样的对象,只会返回一次。

1.2. multiProcessing.Pool()
1.2.1 Pool([processes[, initializer[, initargs[, maxtasksperchild[, context]]]]])
  • processes:使用的工作进程的数量;若processes是None,默认适用os.cpu_count()返回的数量。
  • initializer:若initializer是None,则每一个工作进程在开始的时候就会调用initializer(*initargs)。
  • maxtasksperchild:工作进程退出前可以完成的任务数,完成后用一个新的工作进程来替代原进程,让闲置的资源释放,maxtasksperchild默认是None,此意味只要Pool存在工作进程就一直存活
  • context: 用在制定工作进程启动时的上下文,一般使用multiprocessing.Pool()或者一个context对象的Pool()方法来创建一个池,两种方法都适当的设置了context。
1.2.2 Pool提供了如下方法
  • apply(func[, args=()[, kwds={}]]) :该函数用于传递不定参数,主进程会被阻塞直到函数执行结束(不建议使用,并且3.x以后不在出现)。
  • apply_async(func[, args=()[, kwds={}[, callback=None]]]):与apply用法一样,但它是非阻塞且支持结果返回进行回调。
  • map(func, iterable[, chunksize=None]):Pool类中的map方法,与内置的map函数用法行为基本一致,它会使进程阻塞直到返回结果。 注意,虽然第二个参数是一个迭代器,但在实际使用中,必须在整个队列都就绪后,程序才会运行子进程。
  • close():关闭进程池(pool),使其不在接受新的任务。
  • terminate():结束工作进程,不在处理未处理的任务。
  • join():主进程阻塞等待子进程的退出,join方法必须在close或terminate之后使用。

2. 线程池

2.1 concurrent.futures.ThreadPoolExectuor()

  ThreadPoolExector()的Exectuor 、Future提供的方法同ProcessPoolExecutor()的类似。