前言
💡 痛点:同步代码执行慢?I/O 密集型任务阻塞?不知道何时用 async?
🎯 解决方案 :从事件循环 到协程 ,从并发任务 到性能优化,手把手教你掌握 Python 异步编程。
为什么要学异步编程?
#mermaid-svg-gunG7YC6bLggYV3O{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-gunG7YC6bLggYV3O .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-gunG7YC6bLggYV3O .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-gunG7YC6bLggYV3O .error-icon{fill:#552222;}#mermaid-svg-gunG7YC6bLggYV3O .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-gunG7YC6bLggYV3O .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-gunG7YC6bLggYV3O .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-gunG7YC6bLggYV3O .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-gunG7YC6bLggYV3O .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-gunG7YC6bLggYV3O .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-gunG7YC6bLggYV3O .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-gunG7YC6bLggYV3O .marker{fill:#333333;stroke:#333333;}#mermaid-svg-gunG7YC6bLggYV3O .marker.cross{stroke:#333333;}#mermaid-svg-gunG7YC6bLggYV3O svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-gunG7YC6bLggYV3O p{margin:0;}#mermaid-svg-gunG7YC6bLggYV3O .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-gunG7YC6bLggYV3O .cluster-label text{fill:#333;}#mermaid-svg-gunG7YC6bLggYV3O .cluster-label span{color:#333;}#mermaid-svg-gunG7YC6bLggYV3O .cluster-label span p{background-color:transparent;}#mermaid-svg-gunG7YC6bLggYV3O .label text,#mermaid-svg-gunG7YC6bLggYV3O span{fill:#333;color:#333;}#mermaid-svg-gunG7YC6bLggYV3O .node rect,#mermaid-svg-gunG7YC6bLggYV3O .node circle,#mermaid-svg-gunG7YC6bLggYV3O .node ellipse,#mermaid-svg-gunG7YC6bLggYV3O .node polygon,#mermaid-svg-gunG7YC6bLggYV3O .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-gunG7YC6bLggYV3O .rough-node .label text,#mermaid-svg-gunG7YC6bLggYV3O .node .label text,#mermaid-svg-gunG7YC6bLggYV3O .image-shape .label,#mermaid-svg-gunG7YC6bLggYV3O .icon-shape .label{text-anchor:middle;}#mermaid-svg-gunG7YC6bLggYV3O .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-gunG7YC6bLggYV3O .rough-node .label,#mermaid-svg-gunG7YC6bLggYV3O .node .label,#mermaid-svg-gunG7YC6bLggYV3O .image-shape .label,#mermaid-svg-gunG7YC6bLggYV3O .icon-shape .label{text-align:center;}#mermaid-svg-gunG7YC6bLggYV3O .node.clickable{cursor:pointer;}#mermaid-svg-gunG7YC6bLggYV3O .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-gunG7YC6bLggYV3O .arrowheadPath{fill:#333333;}#mermaid-svg-gunG7YC6bLggYV3O .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-gunG7YC6bLggYV3O .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-gunG7YC6bLggYV3O .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gunG7YC6bLggYV3O .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-gunG7YC6bLggYV3O .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gunG7YC6bLggYV3O .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-gunG7YC6bLggYV3O .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-gunG7YC6bLggYV3O .cluster text{fill:#333;}#mermaid-svg-gunG7YC6bLggYV3O .cluster span{color:#333;}#mermaid-svg-gunG7YC6bLggYV3O div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-gunG7YC6bLggYV3O .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-gunG7YC6bLggYV3O rect.text{fill:none;stroke-width:0;}#mermaid-svg-gunG7YC6bLggYV3O .icon-shape,#mermaid-svg-gunG7YC6bLggYV3O .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-gunG7YC6bLggYV3O .icon-shape p,#mermaid-svg-gunG7YC6bLggYV3O .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-gunG7YC6bLggYV3O .icon-shape .label rect,#mermaid-svg-gunG7YC6bLggYV3O .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-gunG7YC6bLggYV3O .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-gunG7YC6bLggYV3O .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-gunG7YC6bLggYV3O :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 同步 vs 异步
同步执行
异步执行
⏱️ 阻塞等待
❌ 资源浪费
🐢 I/O 密集型慢
⚡ 非阻塞
✅ 资源高效
🚀 吞吐量高
本文目标: 让你从"会用 async/await 语法"到"理解原理、熟练实战、避免坑"。
一、异步编程核心概念
1.1 同步 vs 异步:为什么需要异步?
异步服务器 同步服务器 客户端 异步服务器 同步服务器 客户端 #mermaid-svg-GwYIdYwiWn2uNgzH{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-GwYIdYwiWn2uNgzH .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-GwYIdYwiWn2uNgzH .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-GwYIdYwiWn2uNgzH .error-icon{fill:#552222;}#mermaid-svg-GwYIdYwiWn2uNgzH .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-GwYIdYwiWn2uNgzH .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-GwYIdYwiWn2uNgzH .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-GwYIdYwiWn2uNgzH .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-GwYIdYwiWn2uNgzH .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-GwYIdYwiWn2uNgzH .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-GwYIdYwiWn2uNgzH .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-GwYIdYwiWn2uNgzH .marker{fill:#333333;stroke:#333333;}#mermaid-svg-GwYIdYwiWn2uNgzH .marker.cross{stroke:#333333;}#mermaid-svg-GwYIdYwiWn2uNgzH svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-GwYIdYwiWn2uNgzH p{margin:0;}#mermaid-svg-GwYIdYwiWn2uNgzH .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-GwYIdYwiWn2uNgzH text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-GwYIdYwiWn2uNgzH .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-GwYIdYwiWn2uNgzH .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-GwYIdYwiWn2uNgzH .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-GwYIdYwiWn2uNgzH .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-GwYIdYwiWn2uNgzH #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-GwYIdYwiWn2uNgzH .sequenceNumber{fill:white;}#mermaid-svg-GwYIdYwiWn2uNgzH #sequencenumber{fill:#333;}#mermaid-svg-GwYIdYwiWn2uNgzH #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-GwYIdYwiWn2uNgzH .messageText{fill:#333;stroke:none;}#mermaid-svg-GwYIdYwiWn2uNgzH .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-GwYIdYwiWn2uNgzH .labelText,#mermaid-svg-GwYIdYwiWn2uNgzH .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-GwYIdYwiWn2uNgzH .loopText,#mermaid-svg-GwYIdYwiWn2uNgzH .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-GwYIdYwiWn2uNgzH .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-GwYIdYwiWn2uNgzH .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-GwYIdYwiWn2uNgzH .noteText,#mermaid-svg-GwYIdYwiWn2uNgzH .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-GwYIdYwiWn2uNgzH .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-GwYIdYwiWn2uNgzH .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-GwYIdYwiWn2uNgzH .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-GwYIdYwiWn2uNgzH .actorPopupMenu{position:absolute;}#mermaid-svg-GwYIdYwiWn2uNgzH .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-GwYIdYwiWn2uNgzH .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-GwYIdYwiWn2uNgzH .actor-man circle,#mermaid-svg-GwYIdYwiWn2uNgzH line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-GwYIdYwiWn2uNgzH :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 阻塞 100ms 请求2/3 排队等待 继续处理请求2 请求1处理中(等待数据库)请求2请求3响应1(总耗时300ms)响应2(总耗时600ms)响应3(总耗时900ms)
异步服务器 客户端 异步服务器 客户端 #mermaid-svg-7oyq0ZuliTwHhVq3{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7oyq0ZuliTwHhVq3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7oyq0ZuliTwHhVq3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7oyq0ZuliTwHhVq3 .error-icon{fill:#552222;}#mermaid-svg-7oyq0ZuliTwHhVq3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7oyq0ZuliTwHhVq3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7oyq0ZuliTwHhVq3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7oyq0ZuliTwHhVq3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7oyq0ZuliTwHhVq3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7oyq0ZuliTwHhVq3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7oyq0ZuliTwHhVq3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7oyq0ZuliTwHhVq3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7oyq0ZuliTwHhVq3 .marker.cross{stroke:#333333;}#mermaid-svg-7oyq0ZuliTwHhVq3 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7oyq0ZuliTwHhVq3 p{margin:0;}#mermaid-svg-7oyq0ZuliTwHhVq3 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-7oyq0ZuliTwHhVq3 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-7oyq0ZuliTwHhVq3 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-7oyq0ZuliTwHhVq3 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-7oyq0ZuliTwHhVq3 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-7oyq0ZuliTwHhVq3 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-7oyq0ZuliTwHhVq3 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-7oyq0ZuliTwHhVq3 .sequenceNumber{fill:white;}#mermaid-svg-7oyq0ZuliTwHhVq3 #sequencenumber{fill:#333;}#mermaid-svg-7oyq0ZuliTwHhVq3 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-7oyq0ZuliTwHhVq3 .messageText{fill:#333;stroke:none;}#mermaid-svg-7oyq0ZuliTwHhVq3 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-7oyq0ZuliTwHhVq3 .labelText,#mermaid-svg-7oyq0ZuliTwHhVq3 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-7oyq0ZuliTwHhVq3 .loopText,#mermaid-svg-7oyq0ZuliTwHhVq3 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-7oyq0ZuliTwHhVq3 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-7oyq0ZuliTwHhVq3 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-7oyq0ZuliTwHhVq3 .noteText,#mermaid-svg-7oyq0ZuliTwHhVq3 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-7oyq0ZuliTwHhVq3 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-7oyq0ZuliTwHhVq3 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-7oyq0ZuliTwHhVq3 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-7oyq0ZuliTwHhVq3 .actorPopupMenu{position:absolute;}#mermaid-svg-7oyq0ZuliTwHhVq3 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-7oyq0ZuliTwHhVq3 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-7oyq0ZuliTwHhVq3 .actor-man circle,#mermaid-svg-7oyq0ZuliTwHhVq3 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-7oyq0ZuliTwHhVq3 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 等待时处理其他任务 请求1请求2请求3处理中(切换任务)响应1(总耗时100ms)响应2(总耗时100ms)响应3(总耗时100ms)
性能对比:
| 场景 | 同步耗时 | 异步耗时 | 提升 |
|---|---|---|---|
| 3 个 I/O 任务(各 100ms) | 300ms | 100ms | 3 倍 |
| 10 个 HTTP 请求(各 500ms) | 5000ms | ~550ms | 9 倍 |
| 100 个数据库查询(各 50ms) | 5000ms | ~200ms | 25 倍 |
1.2 核心概念解析
#mermaid-svg-b1smpgOHfJ8PwMZD{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-b1smpgOHfJ8PwMZD .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-b1smpgOHfJ8PwMZD .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-b1smpgOHfJ8PwMZD .error-icon{fill:#552222;}#mermaid-svg-b1smpgOHfJ8PwMZD .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-b1smpgOHfJ8PwMZD .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-b1smpgOHfJ8PwMZD .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-b1smpgOHfJ8PwMZD .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-b1smpgOHfJ8PwMZD .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-b1smpgOHfJ8PwMZD .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-b1smpgOHfJ8PwMZD .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-b1smpgOHfJ8PwMZD .marker{fill:#333333;stroke:#333333;}#mermaid-svg-b1smpgOHfJ8PwMZD .marker.cross{stroke:#333333;}#mermaid-svg-b1smpgOHfJ8PwMZD svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-b1smpgOHfJ8PwMZD p{margin:0;}#mermaid-svg-b1smpgOHfJ8PwMZD .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-b1smpgOHfJ8PwMZD .cluster-label text{fill:#333;}#mermaid-svg-b1smpgOHfJ8PwMZD .cluster-label span{color:#333;}#mermaid-svg-b1smpgOHfJ8PwMZD .cluster-label span p{background-color:transparent;}#mermaid-svg-b1smpgOHfJ8PwMZD .label text,#mermaid-svg-b1smpgOHfJ8PwMZD span{fill:#333;color:#333;}#mermaid-svg-b1smpgOHfJ8PwMZD .node rect,#mermaid-svg-b1smpgOHfJ8PwMZD .node circle,#mermaid-svg-b1smpgOHfJ8PwMZD .node ellipse,#mermaid-svg-b1smpgOHfJ8PwMZD .node polygon,#mermaid-svg-b1smpgOHfJ8PwMZD .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-b1smpgOHfJ8PwMZD .rough-node .label text,#mermaid-svg-b1smpgOHfJ8PwMZD .node .label text,#mermaid-svg-b1smpgOHfJ8PwMZD .image-shape .label,#mermaid-svg-b1smpgOHfJ8PwMZD .icon-shape .label{text-anchor:middle;}#mermaid-svg-b1smpgOHfJ8PwMZD .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-b1smpgOHfJ8PwMZD .rough-node .label,#mermaid-svg-b1smpgOHfJ8PwMZD .node .label,#mermaid-svg-b1smpgOHfJ8PwMZD .image-shape .label,#mermaid-svg-b1smpgOHfJ8PwMZD .icon-shape .label{text-align:center;}#mermaid-svg-b1smpgOHfJ8PwMZD .node.clickable{cursor:pointer;}#mermaid-svg-b1smpgOHfJ8PwMZD .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-b1smpgOHfJ8PwMZD .arrowheadPath{fill:#333333;}#mermaid-svg-b1smpgOHfJ8PwMZD .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-b1smpgOHfJ8PwMZD .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-b1smpgOHfJ8PwMZD .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-b1smpgOHfJ8PwMZD .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-b1smpgOHfJ8PwMZD .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-b1smpgOHfJ8PwMZD .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-b1smpgOHfJ8PwMZD .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-b1smpgOHfJ8PwMZD .cluster text{fill:#333;}#mermaid-svg-b1smpgOHfJ8PwMZD .cluster span{color:#333;}#mermaid-svg-b1smpgOHfJ8PwMZD div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-b1smpgOHfJ8PwMZD .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-b1smpgOHfJ8PwMZD rect.text{fill:none;stroke-width:0;}#mermaid-svg-b1smpgOHfJ8PwMZD .icon-shape,#mermaid-svg-b1smpgOHfJ8PwMZD .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-b1smpgOHfJ8PwMZD .icon-shape p,#mermaid-svg-b1smpgOHfJ8PwMZD .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-b1smpgOHfJ8PwMZD .icon-shape .label rect,#mermaid-svg-b1smpgOHfJ8PwMZD .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-b1smpgOHfJ8PwMZD .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-b1smpgOHfJ8PwMZD .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-b1smpgOHfJ8PwMZD :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 异步编程核心概念
事件循环
Event Loop
协程
Coroutine
任务
Task
Future
期约
📋 任务调度器
🔄 无限循环
⏭️ 任务切换
🎯 可暂停的函数
✨ async def 定义
⏸️ await 暂停
📦 包装协程
🔄 并发执行
✅ 状态追踪
⏳ 异步结果
📮 占位符
🔗 链式调用
概念对比:
| 概念 | 说明 | 类比 |
|---|---|---|
| 事件循环 | 调度和执行任务的循环 | 餐厅服务员 |
| 协程 | 可暂停/恢复的函数 | 厨师(可暂停做菜) |
| 任务 (Task) | 协程的包装,用于跟踪状态 | 订单 |
| Future/Task | 异步操作的占位符 | 取餐号 |
二、async/await 基础语法
2.1 定义协程函数
python
# ===== 协程函数基础 =====
# 1. 定义协程函数(async def)
import asyncio
async def hello():
"""最简单的协程函数"""
print("Hello!")
# await 会让出控制权
await asyncio.sleep(1)
print("World!")
return "Done"
# 2. 调用协程(不会立即执行)
# hello() # ❌ 不会执行,返回协程对象
# hello() # ❌ 同样不会执行
# 3. 运行协程(必须用事件循环)
async def main():
result = await hello()
print(f"Result: {result}")
# 运行方式 1:asyncio.run()(推荐)
asyncio.run(main())
# 运行方式 2:手动创建事件循环
# loop = asyncio.new_event_loop()
# asyncio.set_event_loop(loop)
# try:
# loop.run_until_complete(main())
# finally:
# loop.close()
2.2 await 关键字详解
python
# ===== await 关键字 =====
async def task1():
print("Task 1: 开始")
await asyncio.sleep(1) # 暂停,等待 1 秒
print("Task 1: 结束")
return "Task 1 结果"
async def task2():
print("Task 2: 开始")
await asyncio.sleep(2) # 暂停,等待 2 秒
print("Task 2: 结束")
return "Task 2 结果"
async def main():
# await 只能用在 async 函数中
result1 = await task1() # 等待 task1 完成
print(f"收到: {result1}")
result2 = await task2() # 等待 task2 完成
print(f"收到: {result2}")
# 运行
asyncio.run(main())
# 输出:
# Task 1: 开始
# Task 1: 结束
# 收到: Task 1 结果
# Task 2: 开始
# Task 2: 结束
# 收到: Task 2 结果
# 总耗时:3 秒(顺序执行)
print("\n" + "="*50 + "\n")
# ===== 并发执行 =====
async def main_concurrent():
# 并发执行两个任务
result1, result2 = await asyncio.gather(
task1(), # 不加 await,传协程对象
task2()
)
print(f"收到: {result1}, {result2}")
asyncio.run(main_concurrent())
# 输出:
# Task 1: 开始
# Task 2: 开始
# Task 1: 结束
# Task 2: 结束
# 收到: Task 1 结果, Task 2 结果
# 总耗时:2 秒(并发执行)
2.3 协程 vs 普通函数
python
# ===== 协程 vs 普通函数 =====
# 普通函数
def sync_function():
return "普通函数返回值"
# 协程函数
async def async_function():
return "协程函数返回值"
# 调用对比
print(f"普通函数: {sync_function()}") # 立即返回
# 协程函数必须用事件循环
async def test():
result = await async_function()
print(f"协程函数: {result}")
asyncio.run(test())
# ===== 类型检查 =====
import inspect
print(f"\n普通函数类型: {type(sync_function)}") # <class 'function'>
print(f"协程函数类型: {type(async_function)}") # <class 'coroutine'>
print(f"协程对象类型: {type(asyncio.run(async_function()))}") # <class 'str'>
print(f"\niscoroutinefunction: {inspect.iscoroutinefunction(async_function)}") # True
print(f"iscoroutinefunction(普通函数): {inspect.iscoroutinefunction(sync_function)}") # False
三、事件循环详解
3.1 事件循环原理
渲染错误: Mermaid 渲染失败: Lexical error on line 1. Unrecognized text. graph flowchart A[事件循 -----^
3.2 事件循环操作
python
# ===== 事件循环操作 =====
import asyncio
import time
async def sample_task(name, duration):
"""示例任务"""
print(f"[{name}] 开始")
await asyncio.sleep(duration)
print(f"[{name}] 结束")
return f"{name} 完成"
async def main():
# 1. 获取当前事件循环
loop = asyncio.get_running_loop()
print(f"运行中的事件循环: {loop}")
# 2. 创建任务
task1 = asyncio.create_task(sample_task("任务1", 1))
task2 = asyncio.create_task(sample_task("任务2", 2))
# 3. 等待任务完成
results = await asyncio.gather(task1, task2)
print(f"结果: {results}")
# 运行
start = time.time()
asyncio.run(main())
print(f"总耗时: {time.time() - start:.2f}秒")
print("\n" + "="*50 + "\n")
# ===== 事件循环的生命周期 =====
async def lifecycle_demo():
"""事件循环生命周期演示"""
# 获取事件循环
loop = asyncio.get_running_loop()
print(f"事件循环 ID: {id(loop)}")
# 创建多个任务
tasks = [
asyncio.create_task(sample_task(f"任务{i}", i))
for i in range(1, 4)
]
# 等待所有任务
await asyncio.gather(*tasks)
print("所有任务完成")
asyncio.run(lifecycle_demo())
3.3 事件循环的高级用法
python
# ===== 事件循环高级用法 =====
import asyncio
from asyncio import Future
async def task_with_future():
"""手动创建 Future"""
loop = asyncio.get_running_loop()
# 创建 Future
future = loop.create_future()
# 在另一个任务中设置结果
async def set_result():
await asyncio.sleep(1)
future.set_result("Future 完成!")
# 并发执行
await asyncio.gather(
set_result(),
future # 等待 future 完成
)
print(f"Future 结果: {future.result()}")
asyncio.run(task_with_future())
print("\n" + "="*50 + "\n")
# ===== 延迟执行 =====
async def delayed_execution():
"""延迟执行任务"""
# 方法 1:asyncio.sleep(推荐)
print("1. 开始 sleep")
await asyncio.sleep(2) # 等待 2 秒
print("1. Sleep 结束")
# 方法 2:loop.call_later
def callback():
print("2. 定时回调执行")
loop = asyncio.get_running_loop()
handle = loop.call_later(1, callback) # 1 秒后执行
# 方法 3:loop.call_at(绝对时间)
async def delayed_task():
await asyncio.sleep(0.5)
print("3. 延迟任务执行")
await asyncio.sleep(2) # 等待上面的任务
# handle.cancel() # 可以取消定时任务
asyncio.run(delayed_execution())
四、并发任务管理
4.1 asyncio.gather - 并发执行多个协程
python
# ===== asyncio.gather 并发执行 =====
import asyncio
import time
async def http_request(url, delay):
"""模拟 HTTP 请求"""
print(f"请求 {url}...")
await asyncio.sleep(delay)
return f"{url} 响应"
async def main_gather():
"""并发执行多个 HTTP 请求"""
start = time.time()
# 并发执行 5 个请求
urls = [
("https://api.example.com/users", 1),
("https://api.example.com/posts", 0.5),
("https://api.example.com/comments", 0.8),
("https://api.example.com/tags", 0.3),
("https://api.example.com/stats", 1.2),
]
# 使用 gather 并发执行
tasks = [http_request(url, delay) for url, delay in urls]
results = await asyncio.gather(*tasks)
print(f"\n所有响应: {results}")
print(f"总耗时: {time.time() - start:.2f}秒") # ~1.2 秒(最长那个)
asyncio.run(main_gather())
print("\n" + "="*50 + "\n")
# ===== gather 返回异常处理 =====
async def may_fail_task(task_id):
"""可能失败的任务"""
await asyncio.sleep(0.5)
if task_id == 3:
raise ValueError(f"任务 {task_id} 失败!")
return f"任务 {task_id} 完成"
async def main_with_errors():
"""gather 处理异常"""
# 默认行为:任何一个失败,整个 gather 失败
try:
results = await asyncio.gather(
may_fail_task(1),
may_fail_task(2),
may_fail_task(3), # 这个会失败
)
except ValueError as e:
print(f"捕获异常: {e}")
# return_exceptions=True:捕获所有异常
results = await asyncio.gather(
may_fail_task(1),
may_fail_task(2),
may_fail_task(3),
return_exceptions=True # 异常作为结果返回
)
print(f"结果(含异常): {results}")
# 结果: ['任务 1 完成', '任务 2 完成', ValueError('任务 3 失败!')]
asyncio.run(main_with_errors())
4.2 asyncio.create_task - 创建任务
python
# ===== asyncio.create_task 创建任务 =====
import asyncio
import time
async def long_task(name):
"""长时间运行的任务"""
print(f"[{name}] 开始")
await asyncio.sleep(2)
print(f"[{name}] 结束")
return f"{name} 结果"
async def main_task():
"""使用 create_task"""
start = time.time()
# 创建任务(立即开始执行)
task1 = asyncio.create_task(long_task("任务A"))
task2 = asyncio.create_task(long_task("任务B"))
print("任务已创建,开始等待...")
# await 等待任务完成
result1 = await task1
result2 = await task2
print(f"结果: {result1}, {result2}")
print(f"总耗时: {time.time() - start:.2f}秒") # ~2 秒(并发)
asyncio.run(main_task())
print("\n" + "="*50 + "\n")
# ===== Task 状态追踪 =====
async def tracked_task(task_id):
"""带状态追踪的任务"""
await asyncio.sleep(task_id * 0.5)
return f"任务 {task_id}"
async def main_track():
"""追踪任务状态"""
# 创建任务
tasks = [
asyncio.create_task(tracked_task(i))
for i in range(1, 4)
]
# 等待 0.5 秒后检查状态
await asyncio.sleep(0.5)
for i, task in enumerate(tasks, 1):
print(f"任务 {i}: {task.get_name()}, 状态={task.done()}")
# 等待所有任务完成
results = await asyncio.gather(*tasks)
print(f"所有任务完成: {results}")
asyncio.run(main_track())
4.3 asyncio.wait - 等待任务组
python
# ===== asyncio.wait 等待任务组 =====
import asyncio
from asyncio import FIRST_COMPLETED, FIRST_EXCEPTION
async def task(name, delay):
"""示例任务"""
await asyncio.sleep(delay)
return f"{name} 完成"
async def main_wait():
"""使用 asyncio.wait"""
# 创建任务
tasks = [
asyncio.create_task(task("快速任务", 0.5)),
asyncio.create_task(task("中速任务", 1.5)),
asyncio.create_task(task("慢速任务", 3)),
]
# 等待所有任务完成
done, pending = await asyncio.wait(tasks)
print(f"完成: {[t.result() for t in done]}")
# 等待第一个任务完成
tasks = [
asyncio.create_task(task("任务A", 2)),
asyncio.create_task(task("任务B", 1)),
asyncio.create_task(task("任务C", 0.5)),
]
done, pending = await asyncio.wait(
tasks,
return_when=FIRST_COMPLETED # 第一个完成时返回
)
print(f"第一个完成: {[t.result() for t in done]}")
print(f"仍在运行: {len(pending)} 个")
# 取消未完成的任务
for t in pending:
t.cancel()
await asyncio.gather(*pending, return_exceptions=True)
asyncio.run(main_wait())
print("\n" + "="*50 + "\n")
# ===== asyncio.as_completed - 按完成顺序处理 =====
async def main_as_completed():
"""按完成顺序处理结果"""
tasks = [
asyncio.create_task(task(f"任务{i}", i * 0.5))
for i in range(1, 4)
]
# 按完成顺序获取结果
for future in asyncio.as_completed(tasks):
result = await future
print(f"完成: {result}")
asyncio.run(main_as_completed())
# 输出顺序:任务3(0.5s) -> 任务2(1s) -> 任务1(1.5s)
五、异步上下文管理器
5.1 async with 异步上下文管理器
python
# ===== 异步上下文管理器 =====
import asyncio
class AsyncResource:
"""异步资源管理器"""
async def __aenter__(self):
"""进入上下文"""
print("获取资源...")
await asyncio.sleep(0.5) # 模拟获取连接
print("资源已获取")
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
"""退出上下文"""
print("释放资源...")
await asyncio.sleep(0.5) # 模拟释放连接
print("资源已释放")
return False # 不抑制异常
async def main_async_with():
"""使用 async with"""
async with AsyncResource() as resource:
print(f"使用资源: {resource}")
await asyncio.sleep(1) # 模拟使用资源
asyncio.run(main_async_with())
print("\n" + "="*50 + "\n")
# ===== 异步生成器作为上下文管理器 =====
async def async_context_manager():
"""异步生成器作为上下文管理器"""
async def resource_manager():
print("获取资源")
yield "资源句柄"
print("释放资源")
async with resource_manager() as handle:
print(f"使用 {handle}")
await asyncio.sleep(0.5)
asyncio.run(async_context_manager())
5.2 异步迭代器
python
# ===== 异步迭代器 =====
class AsyncIterator:
"""异步迭代器"""
def __init__(self, items):
self.items = items
self.index = 0
def __aiter__(self):
"""返回异步迭代器本身"""
return self
async def __anext__(self):
"""获取下一个元素"""
if self.index >= len(self.items):
raise StopAsyncIteration
item = self.items[self.index]
self.index += 1
await asyncio.sleep(0.1) # 模拟异步操作
return item
async def main_async_iter():
"""使用异步迭代器"""
async for item in AsyncIterator([1, 2, 3, 4, 5]):
print(f"处理: {item}")
asyncio.run(main_async_iter())
print("\n" + "="*50 + "\n")
# ===== 异步生成器 =====
async def async_data_generator(n):
"""异步数据生成器"""
for i in range(n):
await asyncio.sleep(0.5) # 模拟数据获取
yield i # 生成数据
async def main_async_gen():
"""使用异步生成器"""
async for data in async_data_generator(5):
print(f"收到数据: {data}")
asyncio.run(main_async_gen())
六、异步队列
6.1 asyncio.Queue 异步队列
python
# ===== asyncio.Queue 异步队列 =====
import asyncio
async def producer(queue, name, count):
"""生产者"""
for i in range(count):
item = f"{name}-{i}"
await queue.put(item)
print(f"[{name}] 生产: {item}")
await asyncio.sleep(0.5)
# 发送结束信号
await queue.put(None)
async def consumer(queue, name):
"""消费者"""
while True:
item = await queue.get()
if item is None: # 收到结束信号
queue.task_done()
break
print(f"[{name}] 消费: {item}")
await asyncio.sleep(1) # 模拟处理
queue.task_done()
async def main_queue():
"""生产者-消费者模式"""
queue = asyncio.Queue()
# 创建生产者和消费者
producers = [
asyncio.create_task(producer(queue, f"生产者{i}", 3))
for i in range(2)
]
consumers = [
asyncio.create_task(consumer(queue, f"消费者{i}"))
for i in range(2)
]
# 等待所有生产者完成
await asyncio.gather(*producers)
# 发送结束信号(消费者数量)
for _ in consumers:
await queue.put(None)
# 等待所有消费者完成
await asyncio.gather(*consumers)
asyncio.run(main_queue())
print("\n" + "="*50 + "\n")
# ===== Queue 的其他特性 =====
async def queue_features():
"""Queue 的高级特性"""
queue = asyncio.Queue(maxsize=3) # 设置最大容量
# put_nowait / get_nowait(非阻塞)
try:
queue.put_nowait("item1")
queue.put_nowait("item2")
queue.put_nowait("item3")
queue.put_nowait("item4") # 会抛出 Full
except asyncio.QueueFull:
print("队列已满!")
# 获取队列信息
print(f"队列大小: {queue.qsize()}")
print(f"队列是否为空: {queue.empty()}")
print(f"队列是否满: {queue.full()}")
# 阻塞等待
item = await queue.get()
print(f"获取: {item}")
asyncio.run(queue_features())
七、实战:异步 HTTP 客户端
7.1 使用 aiohttp
python
# ===== aiohttp 异步 HTTP 客户端 =====
# 需要安装:pip install aiohttp
import asyncio
import aiohttp
import time
async def fetch(session, url):
"""获取单个 URL"""
async with session.get(url) as response:
return await response.text()
async def fetch_all(urls):
"""并发获取多个 URL"""
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for url in urls]
results = await asyncio.gather(*tasks, return_exceptions=True)
return results
async def main_aiohttp():
"""aiohttp 实战"""
urls = [
"https://httpbin.org/delay/1",
"https://httpbin.org/delay/2",
"https://httpbin.org/delay/1",
]
start = time.time()
results = await fetch_all(urls)
print(f"完成 {len(results)} 个请求")
print(f"总耗时: {time.time() - start:.2f}秒") # ~2 秒(并发)
for i, result in enumerate(results, 1):
if isinstance(result, Exception):
print(f"请求 {i} 失败: {result}")
else:
print(f"请求 {i} 成功,长度: {len(result)}")
# asyncio.run(main_aiohttp()) # 取消注释运行
print("\n" + "="*50 + "\n")
# ===== 带重试和超时的 HTTP 请求 =====
from aiohttp import ClientError, ClientTimeout
async def fetch_with_retry(session, url, max_retries=3):
"""带重试的请求"""
for attempt in range(max_retries):
try:
async with session.get(url) as response:
if response.status == 200:
return await response.text()
else:
print(f"状态码 {response.status},重试...")
except ClientError as e:
print(f"请求失败(尝试 {attempt+1}/{max_retries}): {e}")
if attempt < max_retries - 1:
await asyncio.sleep(2 ** attempt) # 指数退避
except asyncio.TimeoutError:
print(f"超时(尝试 {attempt+1}/{max_retries})")
if attempt < max_retries - 1:
await asyncio.sleep(2 ** attempt)
return None
async def main_with_retry():
"""带重试的请求实战"""
timeout = ClientTimeout(total=10) # 10 秒超时
async with aiohttp.ClientSession(timeout=timeout) as session:
url = "https://httpbin.org/delay/2"
result = await fetch_with_retry(session, url)
if result:
print(f"成功获取 {len(result)} 字节")
else:
print("请求失败")
# asyncio.run(main_with_retry()) # 取消注释运行
7.2 异步文件操作
python
# ===== 异步文件操作 =====
# 需要安装:pip install aiofiles
import asyncio
import aiofiles
async def async_write():
"""异步写入文件"""
async with aiofiles.open('test.txt', 'w') as f:
await f.write('Hello, ')
await f.write('Async World!')
print("写入完成")
async def async_read():
"""异步读取文件"""
async with aiofiles.open('test.txt', 'r') as f:
content = await f.read()
print(f"读取内容: {content}")
return content
async def main_file():
"""文件操作实战"""
await async_write()
await async_read()
asyncio.run(main_file())
print("\n" + "="*50 + "\n")
# ===== 批量文件处理 =====
async def process_file(filepath):
"""处理单个文件"""
async with aiofiles.open(filepath, 'r') as f:
content = await f.read()
# 模拟处理
await asyncio.sleep(0.1)
return len(content)
async def main_batch_files():
"""批量处理文件"""
# 假设有多个文件
filepaths = [f'file_{i}.txt' for i in range(10)]
# 创建任务
tasks = [process_file(fp) for fp in filepaths]
results = await asyncio.gather(*tasks, return_exceptions=True)
# 统计
success = sum(1 for r in results if isinstance(r, int))
print(f"成功处理 {success} 个文件")
# asyncio.run(main_batch_files()) # 取消注释运行
7.3 异步数据库操作
python
# ===== 异步数据库操作 =====
# 需要安装:pip install aiomysql / pip install asyncpg / pip install aiosqlite
import asyncio
import aiosqlite # SQLite 异步驱动
async def main_database():
"""异步数据库操作"""
# 连接数据库
async with aiosqlite.connect('test.db') as db:
# 创建表
await db.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY,
name TEXT,
email TEXT
)
''')
await db.commit()
# 插入数据
await db.execute(
'INSERT INTO users (name, email) VALUES (?, ?)',
('Alice', 'alice@example.com')
)
await db.execute(
'INSERT INTO users (name, email) VALUES (?, ?)',
('Bob', 'bob@example.com')
)
await db.commit()
# 查询数据
async with db.execute('SELECT * FROM users') as cursor:
rows = await cursor.fetchall()
for row in rows:
print(f"用户: {row}")
# 事务回滚示例
try:
await db.execute('INSERT INTO users VALUES (?, ?, ?)', (1, 'Test', 'test@test.com'))
await db.commit()
except Exception as e:
await db.rollback()
print(f"回滚: {e}")
asyncio.run(main_database())
八、常见问题与最佳实践
8.1 常见错误
python
# ===== 常见错误与解决方案 =====
# ===== 错误 1:在非 async 函数中使用 await =====
def wrong_await():
# await asyncio.sleep(1) # ❌ 语法错误
pass
# ===== 错误 2:忘记 await =====
async def forgot_await():
result = asyncio.sleep(1) # ❌ 不会执行!
print("这里会立即执行")
# 应该:await asyncio.sleep(1)
# ===== 错误 3:混用同步和异步代码 =====
import time
async def mixed_code():
"""混用同步和异步(不推荐)"""
# 同步睡眠(阻塞!)
time.sleep(1) # ❌ 阻塞整个事件循环
# 异步睡眠(非阻塞)
await asyncio.sleep(1) # ✅ 正确
# 同步 I/O(阻塞!)
# with open('file.txt') as f: # ❌ 阻塞!
# content = f.read()
# 异步 I/O(非阻塞)
# async with aiofiles.open('file.txt') as f: # ✅ 正确
# content = await f.read()
# ===== 错误 4:死锁 =====
import threading
async def deadlock_example():
"""可能导致死锁的代码"""
# 在异步代码中使用阻塞的 Lock
lock = threading.Lock() # ❌ 不要用 threading.Lock
# 应该用 asyncio.Lock
async_lock = asyncio.Lock()
async with async_lock:
await asyncio.sleep(1)
print("锁释放")
# ===== 错误 5:异常未捕获 =====
async def unhandled_exception():
"""未处理的异常"""
async def may_fail():
raise ValueError("Oops!")
try:
await may_fail()
except ValueError as e:
print(f"捕获异常: {e}")
asyncio.run(unhandled_exception())
8.2 性能优化技巧
python
# ===== 性能优化技巧 =====
import asyncio
import time
# ===== 技巧 1:批量并发 =====
async def batch_concurrent():
"""批量并发(限制并发数)"""
async def fetch(url):
await asyncio.sleep(0.5)
return f"响应: {url}"
urls = [f"url_{i}" for i in range(100)]
# 限制并发数为 10
semaphore = asyncio.Semaphore(10)
async def bounded_fetch(url):
async with semaphore:
return await fetch(url)
start = time.time()
results = await asyncio.gather(*[bounded_fetch(url) for url in urls])
print(f"100 个请求,并发限制 10,耗时: {time.time() - start:.2f}秒")
asyncio.run(batch_concurrent())
print("\n" + "="*50 + "\n")
# ===== 技巧 2:使用 asyncio.create_task 提前启动 =====
async def early_task_start():
"""提前启动任务"""
async def slow_task():
await asyncio.sleep(2)
return "完成"
start = time.time()
# 方式 1:顺序执行
# result1 = await slow_task()
# result2 = await slow_task()
# 耗时:4 秒
# 方式 2:提前启动任务
task = asyncio.create_task(slow_task()) # 立即开始
await asyncio.sleep(0.5) # 做其他事
result = await task
print(f"提前启动,耗时: {time.time() - start:.2f}秒")
asyncio.run(early_task_start())
print("\n" + "="*50 + "\n")
# ===== 技巧 3:取消任务 =====
async def cancellable_task():
"""可取消的任务"""
async def long_running():
try:
for i in range(10):
print(f"处理 {i}/10")
await asyncio.sleep(1)
return "完成"
except asyncio.CancelledError:
print("任务被取消")
raise
task = asyncio.create_task(long_running())
# 3 秒后取消
await asyncio.sleep(3)
task.cancel()
try:
await task
except asyncio.CancelledError:
print("任务已取消")
asyncio.run(cancellable_task())
8.3 最佳实践清单
#mermaid-svg-WikLhqrUQ2DlWcPX{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-WikLhqrUQ2DlWcPX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-WikLhqrUQ2DlWcPX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-WikLhqrUQ2DlWcPX .error-icon{fill:#552222;}#mermaid-svg-WikLhqrUQ2DlWcPX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-WikLhqrUQ2DlWcPX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-WikLhqrUQ2DlWcPX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-WikLhqrUQ2DlWcPX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-WikLhqrUQ2DlWcPX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-WikLhqrUQ2DlWcPX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-WikLhqrUQ2DlWcPX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-WikLhqrUQ2DlWcPX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-WikLhqrUQ2DlWcPX .marker.cross{stroke:#333333;}#mermaid-svg-WikLhqrUQ2DlWcPX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-WikLhqrUQ2DlWcPX p{margin:0;}#mermaid-svg-WikLhqrUQ2DlWcPX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-WikLhqrUQ2DlWcPX .cluster-label text{fill:#333;}#mermaid-svg-WikLhqrUQ2DlWcPX .cluster-label span{color:#333;}#mermaid-svg-WikLhqrUQ2DlWcPX .cluster-label span p{background-color:transparent;}#mermaid-svg-WikLhqrUQ2DlWcPX .label text,#mermaid-svg-WikLhqrUQ2DlWcPX span{fill:#333;color:#333;}#mermaid-svg-WikLhqrUQ2DlWcPX .node rect,#mermaid-svg-WikLhqrUQ2DlWcPX .node circle,#mermaid-svg-WikLhqrUQ2DlWcPX .node ellipse,#mermaid-svg-WikLhqrUQ2DlWcPX .node polygon,#mermaid-svg-WikLhqrUQ2DlWcPX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-WikLhqrUQ2DlWcPX .rough-node .label text,#mermaid-svg-WikLhqrUQ2DlWcPX .node .label text,#mermaid-svg-WikLhqrUQ2DlWcPX .image-shape .label,#mermaid-svg-WikLhqrUQ2DlWcPX .icon-shape .label{text-anchor:middle;}#mermaid-svg-WikLhqrUQ2DlWcPX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-WikLhqrUQ2DlWcPX .rough-node .label,#mermaid-svg-WikLhqrUQ2DlWcPX .node .label,#mermaid-svg-WikLhqrUQ2DlWcPX .image-shape .label,#mermaid-svg-WikLhqrUQ2DlWcPX .icon-shape .label{text-align:center;}#mermaid-svg-WikLhqrUQ2DlWcPX .node.clickable{cursor:pointer;}#mermaid-svg-WikLhqrUQ2DlWcPX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-WikLhqrUQ2DlWcPX .arrowheadPath{fill:#333333;}#mermaid-svg-WikLhqrUQ2DlWcPX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-WikLhqrUQ2DlWcPX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-WikLhqrUQ2DlWcPX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WikLhqrUQ2DlWcPX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-WikLhqrUQ2DlWcPX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WikLhqrUQ2DlWcPX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-WikLhqrUQ2DlWcPX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-WikLhqrUQ2DlWcPX .cluster text{fill:#333;}#mermaid-svg-WikLhqrUQ2DlWcPX .cluster span{color:#333;}#mermaid-svg-WikLhqrUQ2DlWcPX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-WikLhqrUQ2DlWcPX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-WikLhqrUQ2DlWcPX rect.text{fill:none;stroke-width:0;}#mermaid-svg-WikLhqrUQ2DlWcPX .icon-shape,#mermaid-svg-WikLhqrUQ2DlWcPX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-WikLhqrUQ2DlWcPX .icon-shape p,#mermaid-svg-WikLhqrUQ2DlWcPX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-WikLhqrUQ2DlWcPX .icon-shape .label rect,#mermaid-svg-WikLhqrUQ2DlWcPX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-WikLhqrUQ2DlWcPX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-WikLhqrUQ2DlWcPX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-WikLhqrUQ2DlWcPX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 异步编程最佳实践
基础规范
性能优化
错误处理
调试技巧
✅ 使用 asyncio.run() 启动
✅ await 只能在 async 函数中
✅ 避免同步阻塞调用
✅ 使用 Semaphore 限制并发
✅ 提前 create_task
✅ 批量处理
✅ 捕获 CancelledError
✅ 超时处理
✅ 重试机制
✅ 添加日志
✅ 使用 asyncio.current_task()
✅ traceback 打印
九、实战案例
9.1 异步爬虫
python
# ===== 异步爬虫实战 =====
# pip install aiohttp beautifulsoup4
import asyncio
import aiohttp
from bs4 import BeautifulSoup
import time
class AsyncSpider:
"""异步爬虫"""
def __init__(self, concurrency=10):
self.concurrency = concurrency
self.semaphore = asyncio.Semaphore(concurrency)
self.results = []
async def fetch(self, session, url):
"""抓取单个页面"""
async with self.semaphore:
try:
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as response:
if response.status == 200:
html = await response.text()
return html
return None
except Exception as e:
print(f"抓取失败 {url}: {e}")
return None
async def parse(self, html):
"""解析页面"""
if not html:
return []
soup = BeautifulSoup(html, 'html.parser')
# 提取标题
titles = [tag.get_text() for tag in soup.find_all('h2')]
return titles
async def crawl(self, urls):
"""爬取多个页面"""
async with aiohttp.ClientSession() as session:
tasks = [self.fetch(session, url) for url in urls]
htmls = await asyncio.gather(*tasks, return_exceptions=True)
# 解析所有页面
all_titles = []
for html in htmls:
if isinstance(html, str):
titles = await self.parse(html)
all_titles.extend(titles)
return all_titles
async def main_spider():
"""爬虫主函数"""
spider = AsyncSpider(concurrency=5)
urls = [
f"https://example.com/page{i}"
for i in range(10)
]
start = time.time()
titles = await spider.crawl(urls)
print(f"抓取 {len(titles)} 个标题")
print(f"耗时: {time.time() - start:.2f}秒")
# asyncio.run(main_spider()) # 取消注释运行
9.2 异步 API 服务
python
# ===== 异步 API 服务 =====
# pip install fastapi uvicorn
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import asyncio
app = FastAPI()
# 模拟数据库
items = {}
class Item(BaseModel):
name: str
description: str = None
price: float
@app.post("/items/")
async def create_item(item: Item):
"""创建项目"""
await asyncio.sleep(0.1) # 模拟数据库操作
items[item.name] = item
return item
@app.get("/items/{item_name}")
async def get_item(item_name: str):
"""获取项目"""
await asyncio.sleep(0.1)
if item_name not in items:
raise HTTPException(status_code=404, detail="Item not found")
return items[item_name]
@app.get("/items/")
async def list_items():
"""列出所有项目"""
await asyncio.sleep(0.1)
return list(items.values())
# 运行:uvicorn main:app --reload
9.3 异步定时任务
python
# ===== 异步定时任务 =====
import asyncio
from datetime import datetime
class AsyncScheduler:
"""简单的异步调度器"""
def __init__(self):
self.tasks = []
async def periodic_task(self, interval, func, *args, **kwargs):
"""定期执行任务"""
while True:
try:
await func(*args, **kwargs)
except Exception as e:
print(f"任务执行失败: {e}")
await asyncio.sleep(interval)
def schedule(self, interval, func, *args, **kwargs):
"""调度定期任务"""
task = asyncio.create_task(
self.periodic_task(interval, func, *args, **kwargs)
)
self.tasks.append(task)
return task
async def run(self):
"""运行调度器"""
await asyncio.gather(*self.tasks)
# 使用示例
async def print_time():
print(f"当前时间: {datetime.now().strftime('%H:%M:%S')}")
async def main_scheduler():
scheduler = AsyncScheduler()
# 每 3 秒执行一次
scheduler.schedule(3, print_time)
# 10 秒后停止
await asyncio.sleep(10)
# 取消所有任务
for task in scheduler.tasks:
task.cancel()
await asyncio.gather(*scheduler.tasks, return_exceptions=True)
# asyncio.run(main_scheduler()) # 取消注释运行
十、总结
10.1 知识体系总结
#mermaid-svg-T2dMuXfDxkbssHdC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-T2dMuXfDxkbssHdC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-T2dMuXfDxkbssHdC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-T2dMuXfDxkbssHdC .error-icon{fill:#552222;}#mermaid-svg-T2dMuXfDxkbssHdC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-T2dMuXfDxkbssHdC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-T2dMuXfDxkbssHdC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-T2dMuXfDxkbssHdC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-T2dMuXfDxkbssHdC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-T2dMuXfDxkbssHdC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-T2dMuXfDxkbssHdC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-T2dMuXfDxkbssHdC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-T2dMuXfDxkbssHdC .marker.cross{stroke:#333333;}#mermaid-svg-T2dMuXfDxkbssHdC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-T2dMuXfDxkbssHdC p{margin:0;}#mermaid-svg-T2dMuXfDxkbssHdC .edge{stroke-width:3;}#mermaid-svg-T2dMuXfDxkbssHdC .section--1 rect,#mermaid-svg-T2dMuXfDxkbssHdC .section--1 path,#mermaid-svg-T2dMuXfDxkbssHdC .section--1 circle,#mermaid-svg-T2dMuXfDxkbssHdC .section--1 polygon,#mermaid-svg-T2dMuXfDxkbssHdC .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .section--1 text{fill:#ffffff;}#mermaid-svg-T2dMuXfDxkbssHdC .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-T2dMuXfDxkbssHdC .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .edge-depth--1{stroke-width:17;}#mermaid-svg-T2dMuXfDxkbssHdC .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled,#mermaid-svg-T2dMuXfDxkbssHdC .disabled circle,#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:lightgray;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:#efefef;}#mermaid-svg-T2dMuXfDxkbssHdC .section-0 rect,#mermaid-svg-T2dMuXfDxkbssHdC .section-0 path,#mermaid-svg-T2dMuXfDxkbssHdC .section-0 circle,#mermaid-svg-T2dMuXfDxkbssHdC .section-0 polygon,#mermaid-svg-T2dMuXfDxkbssHdC .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-T2dMuXfDxkbssHdC .section-0 text{fill:black;}#mermaid-svg-T2dMuXfDxkbssHdC .node-icon-0{font-size:40px;color:black;}#mermaid-svg-T2dMuXfDxkbssHdC .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-T2dMuXfDxkbssHdC .edge-depth-0{stroke-width:14;}#mermaid-svg-T2dMuXfDxkbssHdC .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled,#mermaid-svg-T2dMuXfDxkbssHdC .disabled circle,#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:lightgray;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:#efefef;}#mermaid-svg-T2dMuXfDxkbssHdC .section-1 rect,#mermaid-svg-T2dMuXfDxkbssHdC .section-1 path,#mermaid-svg-T2dMuXfDxkbssHdC .section-1 circle,#mermaid-svg-T2dMuXfDxkbssHdC .section-1 polygon,#mermaid-svg-T2dMuXfDxkbssHdC .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .section-1 text{fill:black;}#mermaid-svg-T2dMuXfDxkbssHdC .node-icon-1{font-size:40px;color:black;}#mermaid-svg-T2dMuXfDxkbssHdC .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .edge-depth-1{stroke-width:11;}#mermaid-svg-T2dMuXfDxkbssHdC .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled,#mermaid-svg-T2dMuXfDxkbssHdC .disabled circle,#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:lightgray;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:#efefef;}#mermaid-svg-T2dMuXfDxkbssHdC .section-2 rect,#mermaid-svg-T2dMuXfDxkbssHdC .section-2 path,#mermaid-svg-T2dMuXfDxkbssHdC .section-2 circle,#mermaid-svg-T2dMuXfDxkbssHdC .section-2 polygon,#mermaid-svg-T2dMuXfDxkbssHdC .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .section-2 text{fill:#ffffff;}#mermaid-svg-T2dMuXfDxkbssHdC .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-T2dMuXfDxkbssHdC .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .edge-depth-2{stroke-width:8;}#mermaid-svg-T2dMuXfDxkbssHdC .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled,#mermaid-svg-T2dMuXfDxkbssHdC .disabled circle,#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:lightgray;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:#efefef;}#mermaid-svg-T2dMuXfDxkbssHdC .section-3 rect,#mermaid-svg-T2dMuXfDxkbssHdC .section-3 path,#mermaid-svg-T2dMuXfDxkbssHdC .section-3 circle,#mermaid-svg-T2dMuXfDxkbssHdC .section-3 polygon,#mermaid-svg-T2dMuXfDxkbssHdC .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .section-3 text{fill:black;}#mermaid-svg-T2dMuXfDxkbssHdC .node-icon-3{font-size:40px;color:black;}#mermaid-svg-T2dMuXfDxkbssHdC .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .edge-depth-3{stroke-width:5;}#mermaid-svg-T2dMuXfDxkbssHdC .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled,#mermaid-svg-T2dMuXfDxkbssHdC .disabled circle,#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:lightgray;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:#efefef;}#mermaid-svg-T2dMuXfDxkbssHdC .section-4 rect,#mermaid-svg-T2dMuXfDxkbssHdC .section-4 path,#mermaid-svg-T2dMuXfDxkbssHdC .section-4 circle,#mermaid-svg-T2dMuXfDxkbssHdC .section-4 polygon,#mermaid-svg-T2dMuXfDxkbssHdC .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .section-4 text{fill:black;}#mermaid-svg-T2dMuXfDxkbssHdC .node-icon-4{font-size:40px;color:black;}#mermaid-svg-T2dMuXfDxkbssHdC .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .edge-depth-4{stroke-width:2;}#mermaid-svg-T2dMuXfDxkbssHdC .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled,#mermaid-svg-T2dMuXfDxkbssHdC .disabled circle,#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:lightgray;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:#efefef;}#mermaid-svg-T2dMuXfDxkbssHdC .section-5 rect,#mermaid-svg-T2dMuXfDxkbssHdC .section-5 path,#mermaid-svg-T2dMuXfDxkbssHdC .section-5 circle,#mermaid-svg-T2dMuXfDxkbssHdC .section-5 polygon,#mermaid-svg-T2dMuXfDxkbssHdC .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .section-5 text{fill:black;}#mermaid-svg-T2dMuXfDxkbssHdC .node-icon-5{font-size:40px;color:black;}#mermaid-svg-T2dMuXfDxkbssHdC .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .edge-depth-5{stroke-width:-1;}#mermaid-svg-T2dMuXfDxkbssHdC .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled,#mermaid-svg-T2dMuXfDxkbssHdC .disabled circle,#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:lightgray;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:#efefef;}#mermaid-svg-T2dMuXfDxkbssHdC .section-6 rect,#mermaid-svg-T2dMuXfDxkbssHdC .section-6 path,#mermaid-svg-T2dMuXfDxkbssHdC .section-6 circle,#mermaid-svg-T2dMuXfDxkbssHdC .section-6 polygon,#mermaid-svg-T2dMuXfDxkbssHdC .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .section-6 text{fill:black;}#mermaid-svg-T2dMuXfDxkbssHdC .node-icon-6{font-size:40px;color:black;}#mermaid-svg-T2dMuXfDxkbssHdC .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .edge-depth-6{stroke-width:-4;}#mermaid-svg-T2dMuXfDxkbssHdC .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled,#mermaid-svg-T2dMuXfDxkbssHdC .disabled circle,#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:lightgray;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:#efefef;}#mermaid-svg-T2dMuXfDxkbssHdC .section-7 rect,#mermaid-svg-T2dMuXfDxkbssHdC .section-7 path,#mermaid-svg-T2dMuXfDxkbssHdC .section-7 circle,#mermaid-svg-T2dMuXfDxkbssHdC .section-7 polygon,#mermaid-svg-T2dMuXfDxkbssHdC .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .section-7 text{fill:black;}#mermaid-svg-T2dMuXfDxkbssHdC .node-icon-7{font-size:40px;color:black;}#mermaid-svg-T2dMuXfDxkbssHdC .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .edge-depth-7{stroke-width:-7;}#mermaid-svg-T2dMuXfDxkbssHdC .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled,#mermaid-svg-T2dMuXfDxkbssHdC .disabled circle,#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:lightgray;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:#efefef;}#mermaid-svg-T2dMuXfDxkbssHdC .section-8 rect,#mermaid-svg-T2dMuXfDxkbssHdC .section-8 path,#mermaid-svg-T2dMuXfDxkbssHdC .section-8 circle,#mermaid-svg-T2dMuXfDxkbssHdC .section-8 polygon,#mermaid-svg-T2dMuXfDxkbssHdC .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .section-8 text{fill:black;}#mermaid-svg-T2dMuXfDxkbssHdC .node-icon-8{font-size:40px;color:black;}#mermaid-svg-T2dMuXfDxkbssHdC .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .edge-depth-8{stroke-width:-10;}#mermaid-svg-T2dMuXfDxkbssHdC .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled,#mermaid-svg-T2dMuXfDxkbssHdC .disabled circle,#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:lightgray;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:#efefef;}#mermaid-svg-T2dMuXfDxkbssHdC .section-9 rect,#mermaid-svg-T2dMuXfDxkbssHdC .section-9 path,#mermaid-svg-T2dMuXfDxkbssHdC .section-9 circle,#mermaid-svg-T2dMuXfDxkbssHdC .section-9 polygon,#mermaid-svg-T2dMuXfDxkbssHdC .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .section-9 text{fill:black;}#mermaid-svg-T2dMuXfDxkbssHdC .node-icon-9{font-size:40px;color:black;}#mermaid-svg-T2dMuXfDxkbssHdC .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .edge-depth-9{stroke-width:-13;}#mermaid-svg-T2dMuXfDxkbssHdC .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled,#mermaid-svg-T2dMuXfDxkbssHdC .disabled circle,#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:lightgray;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:#efefef;}#mermaid-svg-T2dMuXfDxkbssHdC .section-10 rect,#mermaid-svg-T2dMuXfDxkbssHdC .section-10 path,#mermaid-svg-T2dMuXfDxkbssHdC .section-10 circle,#mermaid-svg-T2dMuXfDxkbssHdC .section-10 polygon,#mermaid-svg-T2dMuXfDxkbssHdC .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .section-10 text{fill:black;}#mermaid-svg-T2dMuXfDxkbssHdC .node-icon-10{font-size:40px;color:black;}#mermaid-svg-T2dMuXfDxkbssHdC .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .edge-depth-10{stroke-width:-16;}#mermaid-svg-T2dMuXfDxkbssHdC .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled,#mermaid-svg-T2dMuXfDxkbssHdC .disabled circle,#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:lightgray;}#mermaid-svg-T2dMuXfDxkbssHdC .disabled text{fill:#efefef;}#mermaid-svg-T2dMuXfDxkbssHdC .section-root rect,#mermaid-svg-T2dMuXfDxkbssHdC .section-root path,#mermaid-svg-T2dMuXfDxkbssHdC .section-root circle,#mermaid-svg-T2dMuXfDxkbssHdC .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-T2dMuXfDxkbssHdC .section-root text{fill:#ffffff;}#mermaid-svg-T2dMuXfDxkbssHdC .section-root span{color:#ffffff;}#mermaid-svg-T2dMuXfDxkbssHdC .section-2 span{color:#ffffff;}#mermaid-svg-T2dMuXfDxkbssHdC .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-T2dMuXfDxkbssHdC .edge{fill:none;}#mermaid-svg-T2dMuXfDxkbssHdC .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-T2dMuXfDxkbssHdC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Python
异步编程
基础语法
async def
await
协程对象
事件循环
get_running_loop
run_until_complete
create_task
并发任务
gather
wait
as_completed
create_task
异步工具
Queue
Semaphore
Lock
Event
异步生态
aiohttp
aiofiles
aiomysql
FastAPI
最佳实践
避免阻塞
限制并发
错误处理
超时控制
10.2 学习路线图
#mermaid-svg-EKHyTKkVTFNt39en{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-EKHyTKkVTFNt39en .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-EKHyTKkVTFNt39en .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-EKHyTKkVTFNt39en .error-icon{fill:#552222;}#mermaid-svg-EKHyTKkVTFNt39en .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-EKHyTKkVTFNt39en .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-EKHyTKkVTFNt39en .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-EKHyTKkVTFNt39en .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-EKHyTKkVTFNt39en .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-EKHyTKkVTFNt39en .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-EKHyTKkVTFNt39en .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-EKHyTKkVTFNt39en .marker{fill:#333333;stroke:#333333;}#mermaid-svg-EKHyTKkVTFNt39en .marker.cross{stroke:#333333;}#mermaid-svg-EKHyTKkVTFNt39en svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-EKHyTKkVTFNt39en p{margin:0;}#mermaid-svg-EKHyTKkVTFNt39en .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-EKHyTKkVTFNt39en .cluster-label text{fill:#333;}#mermaid-svg-EKHyTKkVTFNt39en .cluster-label span{color:#333;}#mermaid-svg-EKHyTKkVTFNt39en .cluster-label span p{background-color:transparent;}#mermaid-svg-EKHyTKkVTFNt39en .label text,#mermaid-svg-EKHyTKkVTFNt39en span{fill:#333;color:#333;}#mermaid-svg-EKHyTKkVTFNt39en .node rect,#mermaid-svg-EKHyTKkVTFNt39en .node circle,#mermaid-svg-EKHyTKkVTFNt39en .node ellipse,#mermaid-svg-EKHyTKkVTFNt39en .node polygon,#mermaid-svg-EKHyTKkVTFNt39en .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-EKHyTKkVTFNt39en .rough-node .label text,#mermaid-svg-EKHyTKkVTFNt39en .node .label text,#mermaid-svg-EKHyTKkVTFNt39en .image-shape .label,#mermaid-svg-EKHyTKkVTFNt39en .icon-shape .label{text-anchor:middle;}#mermaid-svg-EKHyTKkVTFNt39en .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-EKHyTKkVTFNt39en .rough-node .label,#mermaid-svg-EKHyTKkVTFNt39en .node .label,#mermaid-svg-EKHyTKkVTFNt39en .image-shape .label,#mermaid-svg-EKHyTKkVTFNt39en .icon-shape .label{text-align:center;}#mermaid-svg-EKHyTKkVTFNt39en .node.clickable{cursor:pointer;}#mermaid-svg-EKHyTKkVTFNt39en .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-EKHyTKkVTFNt39en .arrowheadPath{fill:#333333;}#mermaid-svg-EKHyTKkVTFNt39en .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-EKHyTKkVTFNt39en .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-EKHyTKkVTFNt39en .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EKHyTKkVTFNt39en .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-EKHyTKkVTFNt39en .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EKHyTKkVTFNt39en .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-EKHyTKkVTFNt39en .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-EKHyTKkVTFNt39en .cluster text{fill:#333;}#mermaid-svg-EKHyTKkVTFNt39en .cluster span{color:#333;}#mermaid-svg-EKHyTKkVTFNt39en div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-EKHyTKkVTFNt39en .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-EKHyTKkVTFNt39en rect.text{fill:none;stroke-width:0;}#mermaid-svg-EKHyTKkVTFNt39en .icon-shape,#mermaid-svg-EKHyTKkVTFNt39en .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-EKHyTKkVTFNt39en .icon-shape p,#mermaid-svg-EKHyTKkVTFNt39en .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-EKHyTKkVTFNt39en .icon-shape .label rect,#mermaid-svg-EKHyTKkVTFNt39en .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-EKHyTKkVTFNt39en .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-EKHyTKkVTFNt39en .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-EKHyTKkVTFNt39en :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 入门
基础
进阶
精通
• 理解同步 vs 异步
• async/await 语法
• 运行第一个协程
• 事件循环原理
• gather 并发执行
• 异步上下文管理器
• Queue/Semaphore
• aiohttp/aiofiles
• 性能优化技巧
• 异步框架开发
• 自定义异步库
• 生产环境部署
10.3 推荐资源
| 类型 | 资源 | 说明 |
|---|---|---|
| 官方文档 | asyncio --- 异步 I/O | https://docs.python.org/3/library/asyncio.html |
| 官方文档 | 异步编程指引 | https://docs.python.org/3/library/asyncio-dev-guide.html |
| 书籍 | 《Fluent Python》 | 深入讲解异步编程 |
| 课程 | Real Python - Async | 免费教程 |
| 工具 | py-spy | 异步代码性能分析 |
| 工具 | uvloop | 高性能事件循环 |
附录:常用 API 速查
A. 核心函数
python
# asyncio.run() - 运行协程
asyncio.run(coro())
# asyncio.create_task() - 创建任务
task = asyncio.create_task(coro())
# asyncio.gather() - 并发执行
results = await asyncio.gather(*coros)
# asyncio.wait() - 等待任务
done, pending = await asyncio.wait(tasks)
# asyncio.sleep() - 异步睡眠
await asyncio.sleep(seconds)
# asyncio.current_task() - 获取当前任务
task = asyncio.current_task()
# asyncio.all_tasks() - 获取所有任务
tasks = asyncio.all_tasks()
B. 队列和锁
python
# Queue
queue = asyncio.Queue()
await queue.put(item)
item = await queue.get()
queue.task_done()
await queue.join()
# Semaphore(限流)
semaphore = asyncio.Semaphore(10)
async with semaphore:
await do_something()
# Lock(异步锁)
lock = asyncio.Lock()
async with lock:
await do_something()
# Event(事件)
event = asyncio.Event()
event.set()
await event.wait()
# Condition(条件)
condition = asyncio.Condition()
async with condition:
await condition.wait()
condition.notify()
本文基于 Python 3.10+ 编写。如有问题欢迎评论区讨论!