京公网安备 11010802034615号
经营许可证编号:京B2-20210330
Python通过future处理并发问题
future初识
通过下面脚本来对future进行一个初步了解:
例子1:普通通过循环的方式
import os
import time
import sys
import requests
POP20_CC = (
"CN IN US ID BR PK NG BD RU JP MX PH VN ET EG DE IR TR CD FR"
).split()
BASE_URL = 'http://flupy.org/data/flags'
DEST_DIR = 'downloads/'
def save_flag(img,filename):
path = os.path.join(DEST_DIR,filename)
with open(path,'wb') as fp:
fp.write(img)
def get_flag(cc):
url = "{}/{cc}/{cc}.gif".format(BASE_URL,cc=cc.lower())
resp = requests.get(url)
return resp.content
def show(text):
print(text,end=" ")
sys.stdout.flush()
def download_many(cc_list):
for cc in sorted(cc_list):
image = get_flag(cc)
show(cc)
save_flag(image,cc.lower()+".gif")
return len(cc_list)
def main(download_many):
t0 = time.time()
count = download_many(POP20_CC)
elapsed = time.time()-t0
msg = "\n{} flags downloaded in {:.2f}s"
print(msg.format(count,elapsed))
if __name__ == '__main__':
main(download_many)
例子2:通过future方式实现,这里对上面的部分代码进行了复用
from concurrent import futures
from flags import save_flag, get_flag, show, main
MAX_WORKERS = 20
def download_one(cc):
image = get_flag(cc)
show(cc)
save_flag(image, cc.lower()+".gif")
return cc
def download_many(cc_list):
workers = min(MAX_WORKERS,len(cc_list))
with futures.ThreadPoolExecutor(workers) as executor:
res = executor.map(download_one, sorted(cc_list))
return len(list(res))
if __name__ == '__main__':
main(download_many)
分别运行三次,两者的平均速度:13.67和1.59s,可以看到差别还是非常大的。
future
future是concurrent.futures模块和asyncio模块的重要组件
从python3.4开始标准库中有两个名为Future的类:concurrent.futures.Future和asyncio.Future
这两个类的作用相同:两个Future类的实例都表示可能完成或者尚未完成的延迟计算。与Twisted中的Deferred类、Tornado框架中的Future类的功能类似
注意:通常情况下自己不应该创建future,而是由并发框架(concurrent.futures或asyncio)实例化
原因:future表示终将发生的事情,而确定某件事情会发生的唯一方式是执行的时间已经安排好,因此只有把某件事情交给concurrent.futures.Executor子类处理时,才会创建concurrent.futures.Future实例。
如:Executor.submit()方法的参数是一个可调用的对象,调用这个方法后会为传入的可调用对象排定时间,并返回一个
future
客户端代码不能应该改变future的状态,并发框架在future表示的延迟计算结束后会改变期物的状态,我们无法控制计算何时结束。
这两种future都有.done()方法,这个方法不阻塞,返回值是布尔值,指明future链接的可调用对象是否已经执行。客户端代码通常不会询问future是否运行结束,而是会等待通知。因此两个Future类都有.add_done_callback()方法,这个方法只有一个参数,类型是可调用的对象,future运行结束后会调用指定的可调用对象。
.result()方法是在两个Future类中的作用相同:返回可调用对象的结果,或者重新抛出执行可调用的对象时抛出的异常。但是如果future没有运行结束,result方法在两个Futrue类中的行为差别非常大。
对concurrent.futures.Future实例来说,调用.result()方法会阻塞调用方所在的线程,直到有结果可返回,此时,result方法可以接收可选的timeout参数,如果在指定的时间内future没有运行完毕,会抛出TimeoutError异常。
而asyncio.Future.result方法不支持设定超时时间,在获取future结果最好使用yield from结构,但是concurrent.futures.Future不能这样做
不管是asyncio还是concurrent.futures.Future都会有几个函数是返回future,其他函数则是使用future,在最开始的例子中我们使用的Executor.map就是在使用future,返回值是一个迭代器,迭代器的__next__方法调用各个future的result方法,因此我们得到的是各个futrue的结果,而不是future本身
关于future.as_completed函数的使用,这里我们用了两个循环,一个用于创建并排定future,另外一个用于获取future的结果
结果如下:
注意:Python代码是无法控制GIL,标准库中所有执行阻塞型IO操作的函数,在等待操作系统返回结果时都会释放GIL.运行其他线程执行,也正是因为这样,Python线程可以在IO密集型应用中发挥作用
以上都是concurrent.futures启动线程,下面通过它启动进程
concurrent.futures启动进程
concurrent.futures中的ProcessPoolExecutor类把工作分配给多个Python进程处理,因此,如果需要做CPU密集型处理,使用这个模块能绕开GIL,利用所有的CPU核心。
其原理是一个ProcessPoolExecutor创建了N个独立的Python解释器,N是系统上面可用的CPU核数。
使用方法和ThreadPoolExecutor方法一样
数据分析咨询请扫描二维码
若不方便扫码,搜微信号:CDAshujufenxi
在大数据时代背景下,海量行业数据亟需通过专业化工具挖掘潜在价值,辅助企业业务决策、优化运营模式、规避经营风险。Python凭借 ...
2026-08-28SQL是数据分析领域最基础、最核心的工具,承担着取数、清洗、统计、分层、归因的全流程工作。不同于单纯的语法练习,实战化SQL数 ...
2026-08-28 很多企业团队并非缺乏指标,而是陷入“指标失控”:仪表盘上堆满实时跳动的数据,却无法回答“当前瓶颈在哪、下一步该做什么 ...
2026-08-28随着新零售模式的快速普及,零售行业从传统的“货品驱动”全面转向“用户驱动”。门店交易数据、线上消费记录、浏览轨迹、复购频 ...
2026-08-27在数据分析、爬虫采集、接口开发、数据归档等场景中,JSON与CSV是两种使用率最高的数据存储格式。JSON为键值对结构化格式,适配 ...
2026-08-27 很多数据分析师每天都在计算指标、制作报表,但当被问到“什么叫指标数据元”“指标数据标准包含哪些核心维度”“指标数据质 ...
2026-08-27在数据分析工作中,时间序列是最常见的数据类型之一,订单时间、日志时间、交易时段、统计周期等数据均离不开时间处理。原始数据 ...
2026-08-26在数据分析与数据预处理工作中,原始数据普遍存在录入错误、系统故障、偶然极值等问题,极易产生异常数据。异常数据会严重干扰数 ...
2026-08-26 很多数据分析师能熟练写SQL、做透视表,但当被问到“数据是从哪里来的?经过哪些加工才进入数据仓库?ETL具体做了什么?”时 ...
2026-08-26在数理统计与数据分析领域,多因素方差分析与线性回归模型是研究变量关系、因素影响、数据差异规律的两大核心工具。二者均属于经 ...
2026-08-25数据分析的核心价值不在于数据计算与图表制作,而在于清晰、精准、有逻辑地输出结论、支撑业务决策。日常数据分析报告普遍存在结 ...
2026-08-25 很多数据分析师能熟练地写SQL、做透视表、算描述性统计,但当被问到“如何预测用户流失概率”“如何归因销量下滑的关键因素 ...
2026-08-25平均数是数据分析、数理统计与日常运算中最基础、最常用的统计量,核心作用是浓缩一组数据的整体水平、刻画数据集中趋势。在众多 ...
2026-08-24在MySQL数据库中,InnoDB存储引擎作为主流事务型引擎,默认事务隔离级别为可重复读(Repeatable Read,RR),这与SQL Server、Or ...
2026-08-24 很多数据分析师拿到数据就开始清洗、建模,但当被问到“这批数据属于什么类型——结构化还是非结构化?分类变量还是数值变量 ...
2026-08-24 很多数据分析师画过趋势图、做过业绩预测,但当被问到“这个月销售额增长20%,到底是长期趋势自然增长,还是促销活动的短期 ...
2026-08-21在数据分析与数据可视化工作中,直方图是展示数据分布特征、离散程度、集中区间的核心图表,能够直观呈现数值数据的频次分布规律 ...
2026-08-20在数据分析领域有一句核心准则:垃圾数据进,垃圾数据出。数据清洗是数据分析、数据建模、数据可视化之前的必经前置工序,也是保 ...
2026-08-20 很多数据分析师做过按月份的销售额趋势图,画过按天的流量折线图,但当被问到“时间序列和普通数据有什么本质区别”“季节性 ...
2026-08-20在Python数据分析与数据清洗工作中,Pandas是最核心的数据处理库,DataFrame是结构化数据的标准存储格式。在实时数据采集、循环 ...
2026-08-19