Python之线程池

系统启动一个新线程的成本是比较高的,因为它涉及与操作系统的交互。在这种情形下,使用线程池可以很好地提升性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考虑使用线程池。

线程池的基类是concurrent.futures模块中的Executor,Executor提供了两个子类,即ThreadPoolExecutorProcessPoolExecutor,其中ThreadPoolExecutor用于创建线程池,而ProcessPoolExecutor用于创建进程池。

如果使用线程池,那么只要将相应的task函数提交给线程池就行。

主要方法

  • ThreadPoolExecutor(max_works):创建线程池,max_works默认线程数量,默认是cpu数目*5
  • submit(task, *args):将task交给线程池,返回一个Future对象,Future类主要用于获取线程任务函数的返回值。
  • shutdown():关闭线程池

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函数

安装

在python2.7中需要安装futures包才可以使用ThreadPoolExecutor

1
pip install futures

代码演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#encoding=utf-8

import logging
import threading
from concurrent.futures import ThreadPoolExecutor
import time

logging.basicConfig(level = logging.DEBUG, format='%(levelname)s - %(message)s')
logger = logging.getLogger(__name__)


def action(name):
logger.debug('Thread {} is start'.format(name))
return name

# 创建一个包含两条线程的线程池
threadpool = ThreadPoolExecutor(max_workers=2)

# 向线程池中提交一个task, 第二个参数是作为task的函数参数, 返回一个future对象
f1 = threadpool.submit(action, 'thread1')

# 定义task结束完的回调函数,参数数future对象
def f1_callback(f):
logger.debug('f1 is callback')


f1.add_done_callback(f1_callback)

f2 = threadpool.submit(action, 'thread2')

logger.debug('f1 is done:{}'.format(f1.done()))
logger.debug('f2 is done:{}'.format(f2.done()))

logger.debug('f1 result:{}'.format(f1.result()))
logger.debug('f2 result:{}'.format(f2.result()))

结果输出:

1
2
3
4
5
6
7
DEBUG - Thread thread1 is start
DEBUG - f1 is callback
DEBUG - Thread thread2 is start
DEBUG - f1 is done:True
DEBUG - f2 is done:True
DEBUG - f1 result:thread1
DEBUG - f2 result:thread2

总结

使用线程池可以有效地控制系统中并发线程的数量。当系统中包含有大量的并发线程时,会导致系统性能急剧下降,甚至导致Python解释器崩溃,而线程池的最大线程数参数可以控制系统中并发线程的数量不超过此数。


##关联阅读

有用就打赏一下作者吧!