Python线程池

为什么要使用线程池:

1.系统启动一个新线程的成本是比较高的,因为它涉及与操作系统的交互。线程池因为其内线程可以反复利用的特性,能够很好地提高性能,尤其当程序需要创建大量生命周期很短的线程时。

2.一味因为任务数量的增加而增加线程数量,最终会导致线程数量的失控,不仅系统性能会因此急剧下降,甚至会导致Python解释器崩溃。而线程池可以有效地控制系统中并发线程的数量。

如何创建线程池:

创建线程池可以使用concurrent.futures模块中的Executor,Executor提供两个子类:ThreadPoolExecutor ProcessPoolExecutor,其中ThreadPoolExecutor用于创建线程池,而ProcessPoolExecutor用于创建进程池。

1.Executor提供的方法:

  • submit(func,args,kwargs) :将func函数提交给线程池。
  • map(func,iterables,timeout=None.chunksize=1)
    :类似于Python的内置map函数,该函数将会启动多个线程,以异步方式立即对iterables进行map处理。
  • shutdown(wait=True):关闭线程池。

<注意>

1.当程序调用submit()方法将一个func提交给线程池后,submit()方法会返回一个Future对象,Future类主要用于获取线程任务函数的返回值。

2.创建一个线程时,可以指定线程池的最大线程容量,如果不指定那么默认是CPU的核数。另外,创建一个线程池,线程池中自动会创建出指定数目的空闲线程,当我们将一个函数传给线程池后,线程池会自动选择一个空闲线程来执行这个函数。执行完毕后,该线程继续成为空闲状态,而并不会死去。

3.当用shutdown()方法关闭线程池时,仍在运行的线程将会等待其运行完毕后再去关闭,彻底关闭后,线程池中的所有线程都将死亡。

2.Future对象提供的方法:

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

3.线程池创建使用示例

示例1:

from concurrent.futures import ThreadPoolExecutor
import threading
from time import sleep
def info(a,b):
    for i in range(b):
        a += i
    return a
pool = ThreadPoolExecutor(2)
f1 = pool.submit(info,2,3)
f2 = pool.submit(info,4,7)
if f1.done():
    sleep(2)
    print('f1 Result is %d' % (f1.result()))
    f2.cancel()
    if f2.cancelled():
        pool.shutdown()
    else:
        if f2.done():
            sleep(2)
            print('f2 Result is %d' % (f2.result()))
            pool.shutdown()

运行结果:

f1 Result is 5
f2 Result is 25

示例2:

from concurrent.futures import ThreadPoolExecutor
def info(a,b):
    for i in range(b):
        a += i
    return a
with ThreadPoolExecutor(max_workers=2) as pool:
    f1 = pool.submit(info,2,3)
    f2 = pool.submit(info,4,7)
    def get_result(future):
        print('Result is %d' % (future.result()))
    f1.add_done_callback(get_result)
    f2.add_done_callback(get_result)

运行结果:

Result is 5
Result is 25

<分析>

result()函数被调用后,如果不能立即得到返回结果,当前线程会被挂起,比如在示例1中,调用result()方法后,如果info()函数的执行需要很长时间,那么主线程就会被挂起,有什么方法在调用result()方法后即使无法立刻得到结果但是当前线程也不会被挂起呢?


那就需要用到add_done_callback()方法,该方法给future对象添加一个回调函数,添加了回调函数的future对象即使在调用result()方法后无法立即得到返回结果也不会阻塞当前线程,因为回调函数会帮result()把执行结果输出,回调函数会一直等待该线程完成,之后带回结果。

示例3:

from concurrent.futures import ThreadPoolExecutor
def info(a,b):
    for i in range(b):
        a += i
    return a
with ThreadPoolExecutor(2) as pool:
    results = pool.map(info,(2,4),(3,7)) #第一个括号里的是所有线程的第一个参数,以此类推
    for r in results:
        print(r)

运行结果:

5
25

<分析>

传入两组参数,map()方法会自动创建两个线程去执行,创建的线程将会并发执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值