01_什么是异步编程

异步编程就像同时做多件事情,而不是一件一件排队做。想象你在做早餐:普通方式是煮完咖啡再烤面包再煎鸡蛋,需要12分钟;而异步方式是同时启动三个任务,只需要5分钟。本课将用大量生活化的例子,让你彻底理解异步编程的核心思想,并通过实际代码看到2-10倍的性能提升。学完后你将知道什么场景适合用异步,以及为什么异步能让程序更快。


📖 课程目标

  • 用生活例子理解同步和异步的区别
  • 明白为什么需要异步编程
  • 了解异步编程的典型使用场景
  • 看懂第一个对比示例

🍳 生活例子:做早餐

想象你早上要做早餐,需要完成三件事:

  1. 煮咖啡(需要5分钟)
  2. 烤面包(需要3分钟)
  3. 煎鸡蛋(需要4分钟)

方式一:同步方式(一件一件做)

1
2
3
4
5
6
7
8
9
10
11
12
13
你:先煮咖啡 ☕
[站在咖啡机前等待5分钟...]
咖啡好了!

你:再烤面包 🍞
[站在烤箱前等待3分钟...]
面包好了!

你:最后煎鸡蛋 🍳
[站在炉子前等待4分钟...]
鸡蛋好了!

总耗时:5 + 3 + 4 = 12分钟

问题:你大部分时间都在”等待”,效率很低!

方式二:异步方式(同时做多件事)

1
2
3
4
5
6
7
8
9
10
11
你:启动咖啡机 ☕(开始煮)
不等它煮好,立即...

你:放面包进烤箱 🍞(开始烤)
不等它烤好,立即...

你:开始煎鸡蛋 🍳(开始煎)

然后:偶尔看一眼,哪个好了就取出来

总耗时:约5分钟(最长的那个任务)

优势:你在等待的时间里做其他事情,效率提高了!


💻 编程中的同步 vs 异步

同步编程(Synchronous)

就像上面的”方式一”,程序一次只能做一件事:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 同步方式:一个接一个执行
def 下载文件A():
print("开始下载文件A...")
time.sleep(3) # 模拟下载需要3秒
print("文件A下载完成!")

def 下载文件B():
print("开始下载文件B...")
time.sleep(2) # 模拟下载需要2秒
print("文件B下载完成!")

# 执行
下载文件A() # 等3秒
下载文件B() # 再等2秒

# 总耗时:5秒

特点

  • ✅ 简单易懂
  • ✅ 代码执行顺序清晰
  • ❌ 效率低,浪费时间
  • ❌ 在等待时CPU闲着

异步编程(Asynchronous)

就像上面的”方式二”,程序可以同时做多件事:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 异步方式:同时执行
async def 下载文件A():
print("开始下载文件A...")
await asyncio.sleep(3) # 等待时可以做其他事
print("文件A下载完成!")

async def 下载文件B():
print("开始下载文件B...")
await asyncio.sleep(2) # 等待时可以做其他事
print("文件B下载完成!")

# 执行
await asyncio.gather(
下载文件A(),
下载文件B()
)

# 总耗时:3秒(最长的那个)

特点

  • ✅ 效率高,节省时间
  • ✅ 充分利用等待时间
  • ❌ 代码稍微复杂一点
  • ❌ 需要学习新的语法

🎯 为什么需要异步编程?

场景1:网络请求

1
2
3
4
5
6
你的程序:向服务器发送请求
服务器:处理中...(可能需要1秒)
你的程序:傻等着 😴

如果有100个请求,同步方式需要100秒!
异步方式可以同时发送,可能只需要1-2秒!

场景2:文件操作

1
2
3
4
5
你的程序:读取大文件
硬盘:慢慢读取...(可能需要5秒)
你的程序:傻等着 😴

异步方式:在等待文件读取时,可以处理其他任务!

场景3:数据库查询

1
2
3
4
5
你的程序:查询数据库
数据库:搜索中...(可能需要2秒)
你的程序:傻等着 😴

异步方式:可以同时查询多个数据库,或处理其他逻辑!

📊 性能对比

示例:下载10个网页

方式每个网页耗时总耗时效率提升
同步1秒10秒-
异步1秒约1-2秒5-10倍

示例:处理1000个API请求

方式每个请求耗时总耗时效率提升
同步0.5秒500秒(8分钟)-
异步0.5秒约5-10秒50-100倍

🎪 异步编程的典型使用场景

✅ 适合使用异步的场景

  1. 网络请求

    • 爬虫程序(批量抓取网页)
    • API调用(调用第三方服务)
    • 下载文件(批量下载)
  2. 文件操作

    • 读写大量文件
    • 日志处理
    • 数据导入导出
  3. 数据库操作

    • 批量查询
    • 数据同步
    • 报表生成
  4. 实时通信

    • WebSocket服务器
    • 聊天应用
    • 实时推送

❌ 不适合使用异步的场景

  1. CPU密集型任务

    • 复杂计算(科学计算、图像处理)
    • 数据加密解密
    • 视频编码
  2. 简单的顺序任务

    • 只有几个步骤的简单脚本
    • 不涉及等待的快速操作

🔑 核心概念(先有个印象)

1. 协程(Coroutine)

  • 可以暂停和恢复的函数
  • async def 定义
  • 就像可以”暂停”的任务

2. await

  • 等待异步操作完成
  • 在等待时,程序可以去做其他事
  • 就像”我等着,但你可以先忙别的”

3. 事件循环(Event Loop)

  • 负责调度所有异步任务
  • 决定什么时候执行哪个任务
  • 就像一个”任务管理器”

不用担心!这些概念在后面的课程中会详细讲解。


📝 本课小结

核心要点

  1. 同步 = 排队做事(一个接一个)
  2. 异步 = 同时做事(充分利用等待时间)
  3. 异步的优势:在I/O等待时不浪费时间
  4. 异步的适用场景:网络、文件、数据库等需要等待的操作

记住这个类比

1
2
同步 = 银行只有一个窗口,大家排队办理
异步 = 银行有多个窗口,同时为多人服务

🎯 下一步

现在你已经理解了异步编程的基本概念,接下来我们将:

  1. 运行 01_examples.py 看实际效果
  2. 学习 async/await 语法(第2课)
  3. 编写自己的第一个异步程序

准备好了吗?让我们看看实际代码! 👉 运行 python 01_examples.py


💡 思考题

  1. 你的工作中有哪些场景可能用到异步编程?
  2. 如果要同时查询10个不同的API,用同步和异步分别需要多长时间?
  3. 为什么说异步编程不适合CPU密集型任务?

答案在下一课揭晓!😊

附 01_examples.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
"""
第1课示例代码:同步 vs 异步对比

运行方式:
python 01_examples.py
"""

import asyncio
import time
from typing import List


# ============================================
# 示例1:做早餐 - 同步方式 vs 异步方式
# ============================================

def 煮咖啡_同步() -> None:
"""同步方式:煮咖啡"""
print("☕ 开始煮咖啡...")
time.sleep(5) # 模拟煮咖啡需要5秒
print("☕ 咖啡煮好了!")


def 烤面包_同步() -> None:
"""同步方式:烤面包"""
print("🍞 开始烤面包...")
time.sleep(3) # 模拟烤面包需要3秒
print("🍞 面包烤好了!")


def 煎鸡蛋_同步() -> None:
"""同步方式:煎鸡蛋"""
print("🍳 开始煎鸡蛋...")
time.sleep(4) # 模拟煎鸡蛋需要4秒
print("🍳 鸡蛋煎好了!")


def 做早餐_同步方式() -> None:
"""同步方式做早餐:一件一件做"""
print("\n" + "=" * 50)
print("🏃 方式一:同步方式做早餐(一件一件做)")
print("=" * 50)

开始时间 = time.time()

煮咖啡_同步()
烤面包_同步()
煎鸡蛋_同步()

结束时间 = time.time()
总耗时 = 结束时间 - 开始时间

print(f"\n✅ 早餐做好了!总耗时:{总耗时:.1f}秒")
print("💭 分析:我们大部分时间都在等待,效率很低...")


# 异步版本
async def 煮咖啡_异步() -> None:
"""异步方式:煮咖啡"""
print("☕ 开始煮咖啡...")
await asyncio.sleep(5) # 等待时可以做其他事
print("☕ 咖啡煮好了!")


async def 烤面包_异步() -> None:
"""异步方式:烤面包"""
print("🍞 开始烤面包...")
await asyncio.sleep(3) # 等待时可以做其他事
print("🍞 面包烤好了!")


async def 煎鸡蛋_异步() -> None:
"""异步方式:煎鸡蛋"""
print("🍳 开始煎鸡蛋...")
await asyncio.sleep(4) # 等待时可以做其他事
print("🍳 鸡蛋煎好了!")


async def 做早餐_异步方式() -> None:
"""异步方式做早餐:同时做多件事"""
print("\n" + "=" * 50)
print("🚀 方式二:异步方式做早餐(同时做多件事)")
print("=" * 50)

开始时间 = time.time()

# 同时启动三个任务
await asyncio.gather(
煮咖啡_异步(),
烤面包_异步(),
煎鸡蛋_异步()
)

结束时间 = time.time()
总耗时 = 结束时间 - 开始时间

print(f"\n✅ 早餐做好了!总耗时:{总耗时:.1f}秒")
print("💭 分析:在等待的时间里做其他事情,效率大大提高!")


# ============================================
# 示例2:下载文件 - 更实际的例子
# ============================================

def 下载文件_同步(文件名: str, 耗时: int) -> None:
"""同步方式:下载文件"""
print(f"📥 开始下载 {文件名}...")
time.sleep(耗时) # 模拟下载耗时
print(f"✅ {文件名} 下载完成!")


def 批量下载_同步方式() -> None:
"""同步方式:批量下载文件"""
print("\n" + "=" * 50)
print("🏃 同步方式:批量下载5个文件")
print("=" * 50)

开始时间 = time.time()

下载文件_同步("文件1.pdf", 2)
下载文件_同步("文件2.jpg", 3)
下载文件_同步("文件3.mp4", 4)
下载文件_同步("文件4.zip", 2)
下载文件_同步("文件5.doc", 3)

结束时间 = time.time()
总耗时 = 结束时间 - 开始时间

print(f"\n✅ 全部下载完成!总耗时:{总耗时:.1f}秒")


async def 下载文件_异步(文件名: str, 耗时: int) -> None:
"""异步方式:下载文件"""
print(f"📥 开始下载 {文件名}...")
await asyncio.sleep(耗时) # 等待时可以下载其他文件
print(f"✅ {文件名} 下载完成!")


async def 批量下载_异步方式() -> None:
"""异步方式:批量下载文件"""
print("\n" + "=" * 50)
print("🚀 异步方式:批量下载5个文件")
print("=" * 50)

开始时间 = time.time()

# 同时下载所有文件
await asyncio.gather(
下载文件_异步("文件1.pdf", 2),
下载文件_异步("文件2.jpg", 3),
下载文件_异步("文件3.mp4", 4),
下载文件_异步("文件4.zip", 2),
下载文件_异步("文件5.doc", 3)
)

结束时间 = time.time()
总耗时 = 结束时间 - 开始时间

print(f"\n✅ 全部下载完成!总耗时:{总耗时:.1f}秒")
print(f"💡 效率提升:{14/总耗时:.1f}倍!")


# ============================================
# 示例3:性能对比总结
# ============================================

def 性能对比总结() -> None:
"""展示性能对比总结"""
print("\n" + "=" * 50)
print("📊 性能对比总结")
print("=" * 50)
print("""
场景1:做早餐
同步方式:12秒(5+3+4)
异步方式:5秒(最长的任务)
效率提升:2.4倍 ⚡

场景2:下载5个文件
同步方式:14秒(2+3+4+2+3)
异步方式:4秒(最长的任务)
效率提升:3.5倍 ⚡

💡 结论:
当任务涉及"等待"(网络、文件、数据库)时,
异步编程可以大幅提升效率!

等待的任务越多,提升越明显!
""")


# ============================================
# 主程序
# ============================================

async def main() -> None:
"""主程序:运行所有示例"""
print("🎓 第1课:什么是异步编程?")
print("=" * 50)

# 示例1:做早餐
做早餐_同步方式()
await 做早餐_异步方式()

# 示例2:下载文件
批量下载_同步方式()
await 批量下载_异步方式()

# 性能对比
性能对比总结()

print("\n" + "=" * 50)
print("🎉 第1课完成!")
print("=" * 50)
print("""
📚 你学到了什么?
1. 同步 = 排队做事(一个接一个)
2. 异步 = 同时做事(充分利用等待时间)
3. 异步在I/O密集型任务中效率极高

🎯 下一步:
学习 async/await 语法(第2课)

💪 动手练习:
1. 修改上面的等待时间,观察效果变化
2. 增加更多任务,看看效率提升有多大
3. 思考你的工作中哪些场景可以用异步
""")


if __name__ == "__main__":
# 运行主程序
asyncio.run(main())