python基于concurrent模块实现多线程
作者:三只松鼠 发布时间:2023-09-10 18:33:46
目录
引言
操作多线程/多进程
1、创建线程池
2、submit
3、map
4、wait
5、异常处理
引言
之前也写过多线程的博客,用的是 threading ,今天来讲下 python 的另外一个自带库 concurrent 。concurrent 是在 Python3.2 中引入的,只用几行代码就可以编写出线程池/进程池,并且计算型任务效率和 mutiprocessing.pool 提供的 poll 和 ThreadPoll 相比不分伯仲,而且在 IO 型任务由于引入了 Future 的概念效率要高数倍。而 threading 的话还要自己维护相关的队列防止死锁,代码的可读性也会下降,相反 concurrent 提供的线程池却非常的便捷,不用自己操心死锁以及编写线程池代码,由于异步的概念 IO 型任务也更有优势。
concurrent 的确很好用,主要提供了 ThreadPoolExecutor 和 ProcessPoolExecutor 。一个多线程,一个多进程。但 concurrent 本质上都是对 threading 和 mutiprocessing 的封装。看它的源码可以知道,所以最底层并没有异步。
ThreadPoolExecutor 自己提供了任务队列,不需要自己写了。而所谓的线程池,它只是简单的比较当前的 threads 数量和定义的 max_workers 的大小,小于 max_workers 就允许任务创建线程执行任务。
操作多线程/多进程
1、创建线程池
通过 ThreadPoolExecutor 类创建线程池对象,max_workers 设置最大运行线程数数。使用 ThreadPoolExecutor 的好处是不用担心线程死锁问题,让多线程编程更简洁。
from concurrent import futures
pool = futures.ThreadPoolExecutor(max_workers = 2)
2、submit
submit(self, fn, *args, **kwargs):
fn:需要异步执行的函数
*args,**kwargs:fn 接受的参数
该方法的作用就是提交一个可执行的回调task,它返回一个Future对象。可以看出此方法不会阻塞主线程的执行。
import requests,datetime,time
from concurrent import futures
def get_request(url):
r = requests.get(url)
print('{}:{} {}'.format(datetime.datetime.now(),url,r.status_code))
urls = ['https://www.baidu.com','https://www.tmall.com','https://www.jd.com']
pool = futures.ThreadPoolExecutor(max_workers = 2)
for url in urls:
task = pool.submit(get_request,url)
print('{}主线程'.format(datetime.datetime.now()))
time.sleep(2)
# 输出结果
2021-03-12 15:29:10.780141:主线程
2021-03-12 15:29:10.865425:https://www.baidu.com 200
2021-03-12 15:29:10.923062:https://www.tmall.com 200
2021-03-12 15:29:10.940930:https://www.jd.com 200
3、map
map(self, fn, *iterables, timeout=None, chunksize=1):
fn:需要异步执行的函数
*iterables:可迭代对象
map 第二个参数是可迭代对象,比如 list、tuple 等,写法相对简单。map 方法也不会阻塞主线程的执行。
import requests,datetime,time
from concurrent import futures
def get_request(url):
r = requests.get(url)
print('{}:{} {}'.format(datetime.datetime.now(),url,r.status_code))
urls = ['https://www.baidu.com','https://www.tmall.com','https://www.jd.com']
pool = futures.ThreadPoolExecutor(max_workers = 2)
tasks = pool.map(get_request,urls)
print('{}:主线程'.format(datetime.datetime.now()))
time.sleep(2)
# 输出结果
2021-03-12 16:14:04.854452:主线程
2021-03-12 16:14:04.938870:https://www.baidu.com 200
2021-03-12 16:14:05.033849:https://www.jd.com 200
2021-03-12 16:14:05.048952:https://www.tmall.com 200
4、wait
如果要等待子线程执行完之后再执行主线程要怎么办呢,可以通过 wait 。
wait(fs, timeout=None, return_when=ALL_COMPLETED):
fs:所有任务 tasks
return_when:有三个参数 FIRST_COMPLETED:只要有一个子线程完成则返回结果。 FIRST_EXCEPTION:只要有一个子线程抛异常则返回结果,若没有异常则等同于ALL_COMPLETED。 ALL_COMPLETED:默认参数,等待所有子线程完成。
import requests,datetime,time
from concurrent import futures
def get_request(url):
r = requests.get(url)
print('{}:{} {}'.format(datetime.datetime.now(),url,r.status_code))
urls = ['https://www.baidu.com','https://www.tmall.com','https://www.jd.com']
pool = futures.ThreadPoolExecutor(max_workers = 2)
tasks =[]
for url in urls:
task = pool.submit(get_request,url)
tasks.append(task)
futures.wait(tasks)
print('{}:主线程'.format(datetime.datetime.now()))
time.sleep(2)
# 输出结果
2021-03-12 16:30:13.437042:https://www.baidu.com 200
2021-03-12 16:30:13.552700:https://www.jd.com 200
2021-03-12 16:30:14.117325:https://www.tmall.com 200
2021-03-12 16:30:14.118284:主线程
5、异常处理
as_completed(fs, timeout=None)
所有任务 tasks
使用 concurrent.futures 操作 多线程/多进程 过程中,很多函数报错并不会直接终止程序,而是什么都没发生。使用 as_completed 可以捕获异常,代码如下
import requests,datetime,time
from concurrent import futures
def get_request(url):
r = requests.get(url)
print('{}:{} {}'.format(datetime.datetime.now(),url,r.status_code))
urls = ['www.baidu.com','https://www.tmall.com','https://www.jd.com']
# 创建线程池
pool = futures.ThreadPoolExecutor(max_workers = 2)
tasks =[]
for url in urls:
task = pool.submit(get_request,url)
tasks.append(task)
# 异常捕获
errors = futures.as_completed(tasks)
for error in errors:
# error.result() 等待子线程都完成,并抛出异常,中断主线程
# 捕获子线程异常,不会终止主线程继续运行
print(error.exception())
futures.wait(tasks)
print('{}:主线程'.format(datetime.datetime.now()))
time.sleep(2)
# 输出结果
Invalid URL 'www.baidu.com': No schema supplied. Perhaps you meant http://www.baidu.com?
2021-03-12 17:24:26.984933:https://www.tmall.com 200
None
2021-03-12 17:24:26.993939:https://www.jd.com 200
None
2021-03-12 17:24:26.994937:主线程
多进程编程也类似,将 ThreadPoolExecutor 替换成 ProcessPoolExecutor 。
来源:https://www.cnblogs.com/shenh/p/14338173.html


猜你喜欢
- 1.MySQL 5.5命令行里面set global log_slow_queries = on; &nb
- echarts legend点击事件首先,明确本篇文章的重点,主要有三个:1. 给legend添加点击事件2. 禁用legend点击事件的默
- 在当今企业环境中,保证数据安全不是可有可无的工作。频繁曝光的入侵和欺骗事件、萨班斯•奥克斯利法案、HIPAA法案规定和爱国
- 昨天发现程序中数据分析的结果不对,重新进行分析后,原数据仍在,有值的字段被累计。心说,不对啊,是重新生成记录后才分析的啊。难道忘了DELET
- 连接:mysql -h主机地址 -u用户名 -p用户密码 (注:u与root可以不用加空格,其它也一样)断开:exit (回车)创建授权:g
- 什么是goroutine?Goroutine是建立在线程之上的轻量级的抽象。它允许我们以非常低的代价在同一个地址空间中并行地执行多个函数或者
- # -*- coding: utf-8 -*-import Image,ImageDraw,ImageFontimport randomim
- 目录一、两个模块二、SMTP端口三、四大步骤1、构造邮件内容2、连接邮件服务器3、登陆邮件服务器4、发送邮件四、常用场景1、纯文本邮件2、发
- 实验环境:tensorflow版本1.2.0,python2.7介绍depthwise_conv2d来源于深度可分离卷积:Xception:
- 本文实例讲述了Python计算字符宽度的方法。分享给大家供大家参考,具体如下:最近在用python写一个CLI小程序,其中涉及到计算字符宽度
- 后台管理配置动态路由菜单前段时间做一个后台管理项目,因为超级管理员可以给普通管理员动态更改权限,所以vue-element-admin里的写
- PyQt5不规则窗口实现动画效果实例import sysfrom PyQt5.QtCore import *from PyQt5.QtGui
- 隐藏你的.php文件 隐藏你的.php文件 今天做PHP在线手册镜像的时候看到了这个方法,哈哈,以前都没有注意到,所以说,手册是
- 在Udacity上课时学到了python的turtle方法,这是一个很经典的用来教小孩儿编程的图形模块,最早起源于logo语言。python
- 话不多说,请看代码:SQLServer Procedure Pagination_basic:ALTER PROCEDURE [qianch
- 一张表(ColumnTable)的结构如下图所示当前需要实现的功能:通过Number的值为67来获取当前的节点ID、父节点ID递归实现SQL
- 这篇文章主要介绍了JavaScript回调函数callback用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学
- 本文实例讲述了Python PyAutoGUI模块控制鼠标和键盘实现自动化任务。分享给大家供大家参考,具体如下:PyAutoGUI是用Pyt
- Pytorch统计参数网络参数数量def get_parameter_number(net): total_num
- 在网上查找大量资料,经过自己的不懈努力,终于测试成功了。原来要在服务器上安装mysql odbc 3.51 ,还有数据库用户名及密码,用下面