Python 线程池 ThreadPoolExecutor

2023-11-18

线程池

以前我们定义多线程任务的时候都是通过循环来控制线程数量,很不优雅:

import threading


class MyThread(threading.Thread):
    def __init__(self, threadID, name, counter):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.counter = counter

    def run(self):
        print(self.name)

if __name__ == "__main__":

    t_list = []
    for i in range(4):
        name = "线程-" + str(i)
        t = MyThread(i, name, i)
        t.start()
        t_list.append(t)
    for t in t_list:
        t.join()

这样做当然也是可以的,不过一方面是代码有些难看,虽然逻辑上是清晰的,另外一方面是我们无法知道哪个线程完成了,而且控制并发的方式也仅限于给循环的变量不同,说白了还是看起来不舒服。

目标

我们要寻求一种方式既可以实现多线程的效果,让代码看起来优雅一点。而且程序还可以知道哪些任务完成了

线程池

Python3 的线程池是在 concurrent 包下的 ThreadPoolExecutor 来实现的
现在我们写一个简单的线程池例子

from concurrent.futures import ThreadPoolExecutor,
def get_html(times):
    time.sleep(times)
    print("get page {} success".format(times))
    return times
    
executor = ThreadPoolExecutor(max_workers=32)
task1 = executor.submit(get_html, (3))
task2 = executor.submit(get_html, (2))
task3 = executor.submit(get_html, (3))

如果我们想知道哪个任务执行完没有,可以用到 done() 方法

task1.done()

返回是 True 说明执行完了, False 说明没有执行完

在任务 还未开始 的时候我们可以使用 cancel 方法取消,如:task2.cancel()

通过 submit() 函数提交执行的函数到线程池中, 是立即返回,也就是说主线程还是在向下进行的。max_workers 参数是控制同时执行的最大任务数,这里我们有三个任务,但是最大任务数为 2。submit 有两个参数,一个就是所要执行的函数,一定不能加括号,另一个就是函数参数,这里哪怕只有一个参数也要像我这样括起来,不然会出问题!。由于max_workers 是2,一开始有两个在执行,如果有一个先执行完毕了,第三个任务才会开始执行。比起之前的 for 循环要好看不少。

如果有N个任务我们肯定不能一个个定义,用列表生成式就可以:

# ... 其他代码
def get_html(url):
    time.sleep(times)
    print("get page {} success".format(times))
    return times
executor = ThreadPoolExecutor(max_workers=2)
urls = [3,2,4]
all_task = [executor.submit(get_html, (url) ) for url in urls]

高级

我们想看看有多少个任务完成了,可以用 concurrent.futures 里的 as_completed(task) 方法,有一个参数可以是单独的 task 或者一个列表:

# ... 其他代码
all_task = [executor.submit(get_html, (url) ) for url in urls]

for future in as_completed(all_task):
    data = future.result()
    print("get {} page".format(data))

我们的 task 返回值在 future.result()as_completed 在遍历的时候如果有函数执行完了就会返回执行完的结果,以后的任务执行完一个这里就会返回一个,可以理解为 as_completed 会等待任务执行,比如我们这里在遍历的时候只有一个执行完了,那就只会打印一个,如果有第二个执行完了,它就会打印第二个,而且这个也不会影响到主线程。

等待

如果我们想计算一下整个项目执行的时间,但是线程池不会阻塞主线程,就无法实现。

# ... 其他代码

start = time.time()
all_task = [executor.submit(get_html, (url)) for url in urls]
print("all tasks have done,used {}s".format(time.time()-start))

all tasks have done,used 0.0010027885437011719s
get page 2 success
get page 3 success
get page 4 success

可以看到,任务开始以后主线程继续执行了,所以才会看到主线程的打印。

不过 concurrent.futures 给我们提供了一个 wait() 方法,可以让我们等待一个任务执行完,否则一直阻塞在当前位置,当然他也可以传一个列表:

start = time.time()
all_task = [executor.submit(get_html, (url)) for url in urls]
wait(all_task)
print("all tasks have done")

get page 2 success
get page 3 success
get page 4 success
all tasks have done,used 6.002103328704834s

可以看到,这里就会等待所有任务执行完主线程才会继续,至于为什么打印的是 6s 而不是最长线程所用的 4s,是因为我们前面设置了 executor = ThreadPoolExecutor(max_workers=2),限制了它最大的并发数,也就是说 2s 后才会执行第三个任务所以用时就是 2s + 4s = 6s

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python 线程池 ThreadPoolExecutor 的相关文章

随机推荐

  • jQuery empty() vs remove()

    https stackoverflow com questions 3090662 jquery empty vs remove http www cnblogs com yeer archive 2009 06 10 1500682 ht
  • JavaSE复习笔记

    第一章 Java概述 一 计算机语言 机器语言 汇编语言 高级语言 二 跨平台原理 Java可以在一处开发到处运行 即在一类操作系统上开发的程序 可以在任何操作系统上运行 不同的操作系统有不同的JVM java是运行在JVM上 从而实现了跨
  • win7系统打开定位服务器地址,win7 定位服务器地址

    win7 定位服务器地址 内容精选 换一换 您可以通过云日志服务 查看访问七层共享型负载均衡请求的详细日志记录 分析负载均衡的响应状态码 快速定位异常的后端服务器 您已经创建了七层负载均衡 您已经开通了云日志服务 登录管理控制台 在管理控制
  • 函数式组件与类组件有何不同?

    与React类组件相比 React函数式组件究竟有何不同 在过去一段时间里 典型的回答是类组件提供了更多的特性 比如state 当有了Hooks后 答案就不再是这样了 或许你曾听过它们中的某一个在性能上的表现优于另一个 那是哪一个 很多此类
  • MultipartFile实现文件上传和下载(Springboot)

    MultipartFile是SpringMVC提供简化上传操作的工具类 在不使用框架之前 都是使用原生的HttpServletRequest来接收上传的数据 文件是以二进制流传递到后端的 然后需要我们自己转换为File类 使用了Multip
  • 计算机专业选修课怎么选比较好,大一选修课选什么好 大学选修课推荐

    大学之于高中最大的不同点除了越来越多的自由时间以外 大学有各种各样的选修课供我们选择 在专业课之余 还可以选择其他自己感兴趣的学科进行学习 同时也能给自己增加一项技能 大学热门选修课 1 职场礼仪 礼仪是永远不会过时的 它是一个人的修养素质
  • 语法6:raise - 触发异常

    目录 1 基础格式 2 raise 单独语句 3 raise class 4 raise instance 5 raise from 6 try raise 实现循环跳出
  • JDK的命令行工具——修改中

    目录 一 jps 虚拟机进程状况工具 二 jstat 虚拟机统计信息监视工具 三 jinfo java配置信息工具 四 jmap java内存映像工具 五 jhat 虚拟机堆转储快照分析工具 仅做了解即可 六 jstack java堆栈跟踪
  • 以太坊私有网络的设置与体验

    记录一下搭建一个以太坊私有网络环境的过程 方便以后的开发 我这里采用的是Geth客户端 在geth ethereum org网站上有详细的文档介绍 这里主要是按照官网的教程来操作 安装 我是Ubuntu的环境 执行以下命令来安装 sudo
  • 使用hydra进行FTP认证破解

    hydra入门 hydra是什么 hydra的安装 hydra的基本使用 熟悉常见协议 HTTP协议 FTP协议 SSH协议 Telnet协议 熟悉hydra的参数 基本参数 高级参数 使用方法 使用hydra进行HTTP认证破解 HTTP
  • 搭建机器人电控系统——通信协议——串口通信USART/UART、RS232、RS485及其实例

    通信协议 串口通信详解 IIC通信详解 SPI通信详解 CAN通信详解 文章目录 通信协议 什么是串口 串口分类 USART UART RS232 RS485的区别 串口协议原理 传输协议 需要定义的参数 发送函数USART SendDat
  • Java是一门什么语言?

    个人理解 Java代码需要先编译成class 然后交给JVM执行 而JVM在执行class代码时是解释执行的 所以Java不是一门单纯的编译型或解释型语言 它是一门混合型语言 它是集编译型语言和解释型语言的优势于一身 即执行速度较快 只需编
  • 微调(fine-tuning)

    微调 fine tuing 是一种迁移学习 transfer learning 方法 在迁移学习过程中 预训练的模型的权重会根据新数据进行训练和调整
  • Python工程师面试必备25条知识点

    1 到底什么是Python 你可以在回答中与其他技术进行对比 Python是一种解释型语言 与C语言和C的衍生语言不同 Python代码在运行之前不需要编译 其他解释型语言还包括PHP和Ruby Python是动态类型语言 指的是你在声明变
  • Vue实现高德地图信息窗

  • 操作系统——读者写者问题(写者优先)

    阅读前提醒 本文代码为伪代码 仅供理解 马上就要被关得精神失常了 也许这是我的最后一条博客了吧 啊哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈水文来咯 1 什么是读者写者问题 一个数据文件或记录可被多个进程共享
  • 当pytest遇上poium会擦出什么火花 ?

    首先 创建一个test sample test demo py 文件 写入下面三行代码 def test bing page page get https www bing com assert page get title 必应 不要问题
  • 栈和队列-P79-9

    队列的最大容量为MaxSize 这句话并不是说该队列存满时的元素个数为MaxSize 这一种情况是最大容量为MaxSize 没有申请其他数据成员 判断队列满的条件是Q front Q rear 1 MaxSize 解释 通俗的解释 Q re
  • 强化学习:带起始探索的每次访问同策回合更新算法求解机器人找金币问题

    1 问题描述 2 环境建模 3 游戏环境类roadenv 设计 class roadenv def init self epsilon 0 5 gamma 0 8 状态空间 动作空间 self states 1 2 3 4 5 6 7 8
  • Python 线程池 ThreadPoolExecutor

    线程池 以前我们定义多线程任务的时候都是通过循环来控制线程数量 很不优雅 import threading class MyThread threading Thread def init self threadID name counte