Python中的并发编程asyncio库入门使用
前言asyncio是 Python 标准库里的异步框架但它不是「一个函数」而是一整套协作式并发的基础设施。新手常犯的错是把asyncio的 API 当成threading的等价物来用——随手await两下却发现根本没有并发。这篇是API 速查 语义说明先讲清「协作式调度」到底意味着什么再把最常用的几个入口——create_task、gather、wait_for、as_completed、Queue、Semaphore、Lock、to_thread——逐个说清用途和版本。先记一条贯穿全文的语义协程只有在await时才会把控制权交还给事件循环。你写的任何一段不含await的同步代码都会独占循环其他所有任务一起等它。理解这一点下面每个 API 的取舍就都顺了。一、协作式调度意味着什么「协作式」是相对「抢占式」说的。线程由操作系统抢占式调度——时间片到了就强制切换代码管不着。协程反过来必须自己在await处让位。这带来两个实践结果好处切换点完全由你掌控不用担心「改到一半被切走」所以共享数据不需要锁——只要两个协程之间没有await它们就不会交错。坏处一个协程如果长时间不await事件循环就卡住。阻塞调用time.sleep、同步 I/O、大循环是异步程序的头号杀手。# 适用于 Python 3.8import asyncioasync def ticker(name, n):for i in range(n):print(name, i)await asyncio.sleep(0) # await sleep(0) 主动让位一次让别的任务有机会跑async def main():await asyncio.gather(ticker(A, 3), ticker(B, 3))asyncio.run(main())asyncio.sleep(0)是「主动让出一次控制权」的常用技巧它不会真的睡只是把执行权还给循环。二、create_task 与 gather把任务跑起来asyncio.create_task(coro)3.7 新增把协程包装成一个Task并立刻交给事件循环排队。关键区别在于# 适用于 Python 3.8import asyncioasync def work(n):await asyncio.sleep(n)return n * 2async def serial():a await work(1) # 串行等完 1 秒再走下一行b await work(1) # 再等 1 秒总共约 2 秒return a, basync def concurrent():t1 asyncio.create_task(work(1)) # 立刻排队不等它t2 asyncio.create_task(work(1)) # 立刻排队return await asyncio.gather(t1, t2) # 一起等总耗时约 1 秒asyncio.gather(*aws, return_exceptionsFalse)用来等一组任务全部完成并按传入顺序返回结果列表。return_exceptionsTrue时某个任务抛出的异常会当成结果放进列表而不是让gather整体失败。需要说明一个易混点gather里如果某个任务抛异常默认情况下其他任务不会被自动取消它们会继续跑而 3.11 新增的TaskGroup行为不同——组里任一任务失败TaskGroup会把其余任务取消。两者不是简单替代关系。三、wait_for 与 as_completed控制等待方式await asyncio.wait_for(aw, timeout)给单个可等待对象加超时。超时后它会取消该任务并抛asyncio.TimeoutError。# 适用于 Python 3.8import asyncioasync def slow():await asyncio.sleep(10)async def main():try:await asyncio.wait_for(slow(), timeout1.0)except asyncio.TimeoutError:print(超时了)asyncio.as_completed(aws, *, timeoutNone)则是「谁先完成就先处理谁」返回一个可迭代对象。注意它不会取消未完成的任务只是改变你获取结果的顺序适合「先拿到先处理」的场景比如分批写文件。# 适用于 Python 3.83.13 起也可用 async for 迭代import asyncioasync def job(i):await asyncio.sleep(0.1 * i)return iasync def main():tasks [asyncio.create_task(job(i)) for i in range(5)]for fut in asyncio.as_completed(tasks):print(await fut) # 按完成先后打印不是按 0,1,2,3 的顺序在 3.11 及以上如果想在协程里用async with asyncio.timeout(seconds):这种上下文管理器写法也是官方推荐的方式它比wait_for更贴近结构化并发。四、Queue、Semaphore、Lock协作式下的同步原语标准库asyncio提供了自己的一套同步原语不能用queue.Queue或threading.Lock替代——那些是给线程用的阻塞原语放进协程里会卡死循环。asyncio.Queue(maxsize0)maxsize 0表示不限await q.put(x)在队满时挂起await q.get()在队空时挂起。生产者消费者模型标配。配套还有join()与task_done()。asyncio.Semaphore(value1)信号量用来限制同时进行的任务数量。这是控制并发上限最常用的工具。asyncio.Lock互斥锁用async with lock:使用。在纯协程代码里如果临界区没有await其实不需要锁但一旦临界区里有await就可能被其他协程穿插此时需要锁。# 适用于 Python 3.8import asyncioasync def main():sem asyncio.Semaphore(3) # 最多 3 个任务同时进行queue asyncio.Queue()async def worker(n):async with sem: # 超过 3 个就排队等信号量await asyncio.sleep(0.1)await queue.put(n * n)await asyncio.gather(*(worker(i) for i in range(10)))results []while not queue.empty():results.append(queue.get_nowait())print(len(results))信号量的意义就在「把并发上限压到一个合规的值」——这一点在后文讲抓取时会再强调。五、to_thread把同步代码搬离事件循环asyncio.to_thread(func, /, *args, **kwargs)是3.9 新增的。它把同步函数丢到一个线程里执行不阻塞事件循环返回一个可 await 的对象。# 适用于 Python 3.93.8 请用 loop.run_in_executorimport asyncio, timedef blocking_io():time.sleep(1)return doneasync def main():result await asyncio.to_thread(blocking_io)print(result)asyncio.run(main())官方文档特别提醒由于 GIL 的存在to_thread()通常只适合 I/O 密集的函数只有在没有 GIL 的构建上比如自由线程构建它才能用于 CPU 密集函数。所以别指望用to_thread()加速纯计算——那还是要靠进程池。3.8 及更早版本没有to_thread()等价写法是# 适用于 Python 3.8to_thread 出现之前import asyncioasync def main():loop asyncio.get_running_loop()result await loop.run_in_executor(None, blocking_io)print(result)run_in_executor的第一个参数传None表示使用默认的ThreadPoolExecutor。常见坑点连写两个 await 以为是并发❌a await f(); b await g()串行✅a, b await asyncio.gather(f(), g())用time.sleep做异步等待❌async def f(): time.sleep(1)卡死循环✅await asyncio.sleep(1)在协程里用线程版同步原语❌import queue; queue.Queue().get()阻塞事件循环✅await asyncio.Queue().get()创建了 Task 却没保存引用❌asyncio.create_task(f())后不持有返回值任务可能被垃圾回收提前消失✅ 保存到变量或放进集合t asyncio.create_task(f())以为to_thread能加速 CPU 计算❌ 把密集计算丢给to_thread期待提速✅ 认清 GILCPU 密集改用ProcessPoolExecutor把wait_for当成「给任务加超时」❌ 以为超时后子任务自动结束了✅ 超时会取消等待必要时在except里自行清理在 3.11 混用 gather 与 TaskGroup 的异常语义❌ 以为TaskGroup和gather失败后行为一样✅ 记住TaskGroup会连带取消兄弟任务gather默认不会总结API用途版本create_task把协程立即排入事件循环3.7gather并发跑一组并收齐结果3.5wait_for给单个等待加超时3.5as_completed按完成先后取结果3.5Queue/Semaphore/Lock协作式同步原语3.4to_thread把同步函数挪到线程3.9TaskGroup结构化并发任务组3.11asyncio的入门要点只有两条并发要先create_task再统一等等待必须用await而不是阻塞调用。把这两条装进肌肉记忆剩下的 API 都是在这个框架上做加减法。

相关新闻

SMCC特征提取+BP神经网络:玉米种子活力分级实战

SMCC特征提取+BP神经网络:玉米种子活力分级实战

简介:这份PDF文献面向从事玉米种子检测、育种与农业工程的研究人员及机器学习初学者,聚焦种子活力多等级快速无损分级这一实际问题。文中以人工加速老化制备五个活力等级样本,用近红外漫反射光谱仪采集光谱,对比主成分分析与SMCC特…

2026/10/9 9:47:05 阅读更多 →
MiniMaxH3+ComfyUI本地部署:动作迁移与漫剧生成实战指南

MiniMaxH3+ComfyUI本地部署:动作迁移与漫剧生成实战指南

1. 项目概述:这不是“又一个ComfyUI教程”,而是动作迁移与漫剧生成的本地化破局点全网首发!从头开始本地部署MiniMaxH3ComfyUI——这句话里藏着三个被严重低估的关键信号:“MiniMaxH3”不是Stable Diffusion的平替,而是…

2026/10/9 9:47:05 阅读更多 →
基于YOLOv8的植物健康状态检测系统:中英文双版本全流程实战

基于YOLOv8的植物健康状态检测系统:中英文双版本全流程实战

1. 项目缘起与整体设计思路植物健康状态检测这件事,说大不大,说小也不小。往小了说,家里阳台养几盆绿植,叶子发黄了、长斑了,想快速判断是缺水、缺肥还是感染了病菌;往大了说,规模化种植的温室大…

2026/10/9 9:47:05 阅读更多 →

最新新闻

收藏!小白/程序员快速入门大模型:三款AI Coding工具深度解析与实战指南(TaoToken 统一接入版)

收藏!小白/程序员快速入门大模型:三款AI Coding工具深度解析与实战指南(TaoToken 统一接入版)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 14:00:42 阅读更多 →
基于PJ85718DM与PIC18LF46K22的HVAC本地远程双路测温方案

基于PJ85718DM与PIC18LF46K22的HVAC本地远程双路测温方案

1. 从一颗温度传感器说起:为什么本地与远程双路测温在HVAC场景里绕不开做嵌入式暖通空调控制这行的人,大概都有过类似的经历:板子上焊了一颗温度芯片,读出来的数值看着挺正常,可一旦把探头拉到几米外的风管或者水管上&…

2026/10/10 14:00:42 阅读更多 →
CSS滤镜、混合模式与遮罩:从普通页面到高级视觉效果的进阶指南

CSS滤镜、混合模式与遮罩:从普通页面到高级视觉效果的进阶指南

如果你做前端越久,会越来越发现一个现象:同样是图片展示和视觉表现,有人做出来的页面是"好看的网页",有人做出来的是"有质感的设计稿"。差距往往不在切图和标注,而在对视觉层级、色彩关系和图层关…

2026/10/10 14:00:42 阅读更多 →
论文精读:TileLang 的可组合平铺编程模型,凭什么在 NVIDIA/AMD 上追平甚至反超手写库?

论文精读:TileLang 的可组合平铺编程模型,凭什么在 NVIDIA/AMD 上追平甚至反超手写库?

论文精读:TileLang 的可组合平铺编程模型,凭什么在 NVIDIA/AMD 上追平甚至反超手写库? 【免费下载链接】tilelang Domain-specific language designed to streamline the development of high-performance GPU/CPU/Accelerators kernels 项…

2026/10/10 14:00:42 阅读更多 →
嵌入式架构设计利器:AADL与OSATE2建模分析实战

嵌入式架构设计利器:AADL与OSATE2建模分析实战

入行嵌入式软件架构设计这些年,最让我头疼的从来不是写代码,而是开架构评审会。记得有一回,项目负责人摊开一张几十兆的架构图,兴致勃勃地解释系统框图中每个箭头的含义,可当有人问“这条数据路径从采集到执行&#xf…

2026/10/10 14:00:41 阅读更多 →
2026年上海豆包DeepSeekKimi百度AI通义千问GEO服务商选择

2026年上海豆包DeepSeekKimi百度AI通义千问GEO服务商选择

当上海企业开始把品牌内容投向豆包、DeepSeek、Kimi、百度AI、通义千问等中文AI平台时,一个越来越现实的问题会浮现:不是“要不要做GEO”,而是“该和什么样的GEO服务商合作,才能让内容真正被AI看见、理解、引用,并在本…

2026/10/10 13:59:41 阅读更多 →

日新闻

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

卫星轨道分类全解析:从LEO到GEO的选型逻辑与工程实践

1. 从“卫星轨道分类”这个标题说起:为什么值得花时间搞懂第一次接触“卫星轨道分类”这个概念,很多人会觉得它离自己很远——不就是天上的星星怎么转吗?但如果你正在做航天任务规划、遥感数据接收、星座设计,甚至只是准备一场航天…

2026/10/10 0:00:39 阅读更多 →
Spring AOP 核心原理与实战:从概念到日志切面落地

Spring AOP 核心原理与实战:从概念到日志切面落地

1. 从一个真实痛点说起:为什么你的代码里到处都是重复逻辑刚入行那会儿,我写过一个用户管理模块,注册、登录、改密码、注销四个接口。每个接口里都塞了几乎一样的日志打印、参数校验、事务开启和提交。当时觉得没什么,能跑就行。直…

2026/10/10 0:00:40 阅读更多 →
Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

Python招聘数据采集与分析可视化:从采集清洗到薪资技能城市可视化全链路

简介:这是一套面向计算机相关专业学生与项目实战学习者的Python数据采集与分析可视化完整项目,以Boss直聘岗位数据为对象,适合用作毕业设计、课程设计或期末大作业。资源包共38个文件,约246KB,以13个py源码文件为核心&…

2026/10/10 0:00:40 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:25 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 1:36:08 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 11:14:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 5:23:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →