前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python:ThreadPoolExecutor线程池和ProcessPoolExecutor进程池

python:ThreadPoolExecutor线程池和ProcessPoolExecutor进程池

作者头像
雷子
发布2023-12-04 11:40:28
2540
发布2023-12-04 11:40:28
举报

为什么需要线程池呢?

代码语言:javascript
复制
对于io密集型,提高执行的效率。
线程的创建是需要消耗系统资源的。
每个线程各自分配一个任务,剩下的任务排队等待,
  当某个线程完成了任务的时候,排队任务就可以安排给这个线程继续执行。

如何来实现线程池呢?

代码语言:javascript
复制
标准库concurrent.futures模块
  它提供了ThreadPoolExecutor和ProcessPoolExecutor两个类,
   分别实现了对threading模块和multiprocessing模块的进一步抽象。
   不仅可以帮我们自动调度线程,还可以做到:
    - 主线程可以获取某一个线程(或者任务)的状态,以及返回值
    - 当一个线程完成的时候,主线程能够立即知道
    - 让多线程和多进程的编码接口一致

如何用呢?简单代码演示


代码语言:javascript
复制
from concurrent.futures import ThreadPoolExecutor


def get(run):
    print(" {}finished".format(run))

# 创建线程池
# 设置线程池中最多能同时运行的线程数目,其他等待
executor = ThreadPoolExecutor(max_workers=2)

# 通过submit函数提交执行的函数到线程池中,submit函数立即返回,不阻塞
# task1和task2是任务句柄
task1 = executor.submit( get, (2) )
task2 = executor.submit( get, (3) )

结果展示

代码语言:javascript
复制
 2finished
 3finished
代码语言:javascript
复制
# done()方法用于判断某个任务是否完成,bool型,完成返回True,没有完成返回False
print( task1.done() )

# cancel()方法用于取消某个任务,该任务没有放到线程池中才能被取消,如果已经放进线程池子中,则不能被取消
# bool型,成功取消了返回True,没有取消返回False
print( task2.cancel() )

# result()方法可以获取task的执行结果,get()函数有返回值
print( task1.result() )
print( task2.result() )

看下最后的展示

代码语言:javascript
复制
True
False
None
None

因为没有返回结果,所以打印的是None

代码语言:javascript
复制
ThreadPoolExecutor类在构造实例的时候,传入max_workers参数来设置线程池中最多能同时运行的线程数目
使用submit()函数来提交线程需要执行任务(函数名和参数)到线程池中,并返回该任务的句柄,
注意submit()不是阻塞的,而是立即返回。
通过submit()函数返回的任务句柄,能够使用done()方法判断该任务是否结束,使用cancel()方法来取消,
使用result()方法可以获取任务的返回值,查看内部代码,发现该方法是阻塞的

ProcessPoolExecutor多进程


代码语言:javascript
复制

from concurrent.futures import ProcessPoolExecutor
def get(run):
    print(" {}finished".format(run))


if __name__ == '__main__':
    p = ProcessPoolExecutor(4)  # 设置

    for i in range(10):
        # 同步调用方式,不仅要调用,还要等返回值
        obj = p.submit(get, "参数")  # 传参方式(任务名,参数),参数使用位置或者关键字参数
        res = obj.result()
    p.shutdown(wait=True)  # 关闭进程池的入口,等待池内任务运行结束
    print("主")

结果打印;

代码语言:javascript
复制
 参数finished
 参数finished
 参数finished
 参数finished
 参数finished
 参数finished
 参数finished
 参数finished
 参数finished
 参数finished
主

线程池和进程池如何选择呢?

进程池:异步 + 回调函数,cpu密集型,同时执行,每个进程有不同的解释器和内存空间,互不干扰

代码语言:javascript
复制

from concurrent.futures import ProcessPoolExecutor
def get(run):
    print(" {}finished".format(run))

def future(future):
    print(future.result())

if __name__ == '__main__':
    p = ProcessPoolExecutor(4)  # 设置

    for i in range(10):
        # 同步调用方式,不仅要调用,还要等返回值
        obj = p.submit(get, "参数")  # 传参方式(任务名,参数),参数使用位置或者关键字参数
        obj.add_done_callback(future)
    p.shutdown(wait=True)  # 关闭进程池的入口,等待池内任务运行结束
    print("主")

常用的就是我们的爬虫。爬去后解析,解析后存储,会大量使用的cpu。

(2)线程池:异步 + 回调函数,IO密集型主要使用方式,线程池:执行操作为谁有空谁执行

代码语言:javascript
复制
from concurrent.futures import ThreadPoolExecutor
def get(run):
    print(" {}finished".format(run))

def future(future):
    print(future.result())

if __name__ == '__main__':
    p = ThreadPoolExecutor(4)
    start = time.time()
    testcase=[2,3,4,5]
    for case in testcase:
        futu = p.submit(get, case)
        futu.add_done_callback(future)
    p.shutdown(wait=True)

结果展示:

代码语言:javascript
复制
 2finished
None
 3finished
 4finished
None
None
 5finished
None

使用:移动端多用例并行执行的时候,需要设备空闲才执行,我们可以用线程来管理一个设备,设备执行完毕 就下发一个任务。这个最好的方式 可以和队列放在一起去执行。

总结

代码语言:javascript
复制
线程不是越多越好,会涉及cpu上下文的切换(会把上一次的记录保存)。
进程比线程消耗资源,进程相当于一个工厂,工厂里有很多人,里面的人共同享受着福利资源,一个进程里默认只有一个主线程,
计算密度型适用于多进程
线程:线程是计算机中工作的最小单元
进程:默认有主线程 (帮工作)可以多线程共存
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-11-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 雷子说测试开发 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么需要线程池呢?
  • ProcessPoolExecutor多进程
    • 进程池:异步 + 回调函数,cpu密集型,同时执行,每个进程有不同的解释器和内存空间,互不干扰
      • (2)线程池:异步 + 回调函数,IO密集型主要使用方式,线程池:执行操作为谁有空谁执行
      • 总结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档