[Python3高阶编程] - 异步编程深度学习指南一(补充1):深入理解关键词 async
·
async 是 Python 异步编程的基石关键字,它和 await 一起构成了现代 Python 异步 I/O 的核心语法。
一、async 的核心作用
async关键字用于定义“协程函数”(coroutine function)——一种可以暂停和恢复执行的特殊函数。
类比理解:
- 普通函数:像一条直线,从头跑到尾,中间不能停。
- 协程函数(
async def):像一条有“检查点”的跑道,跑到await处可以暂停,让别人先跑,等轮到自己再继续。
二、async 怎么使用?——基本语法
基本形式:
async def function_name(parameters):
# 函数体
await some_async_operation() # 可选,但通常会有
return result
示例 1:最简单的协程函数
async def greet(name):
return f"Hello, {name}!"
# 调用它
coro = greet("Alice")
print(type(coro)) # <class 'coroutine'> —— 返回一个协程对象,不是结果!
⚠️ 注意:调用
greet("Alice")不会立即执行函数体,而是返回一个协程对象(coroutine object)。
三、async def vs 普通 def 的关键区别
全屏复制
| 特性 | def(普通函数) | async def(协程函数) |
|---|---|---|
| 调用返回值 | 直接返回结果 | 返回 协程对象(需 await 或事件循环执行) |
内部能否用 await | ❌ 不能 | ✅ 可以 |
| 执行方式 | 立即执行 | 需由事件循环调度执行 |
| 是否可暂停 | ❌ 不可 | ✅ 在 await 处可暂停 |
四、如何真正“运行”一个协程函数?
仅仅调用 async def 函数不会执行它!你需要以下方式之一:
方式 1:在另一个协程中 await 它(推荐)
async def main():
result = await greet("Bob") # ✅ 真正执行并获取结果
print(result) # Hello, Bob!
方式 2:用 asyncio.run() 启动(顶层入口)
import asyncio
# 在脚本顶层
result = asyncio.run(greet("Charlie"))
print(result) # Hello, Charlie!
方式 3:提交给事件循环(高级)
loop = asyncio.new_event_loop()
task = loop.create_task(greet("David"))
loop.run_until_complete(task)
print(task.result()) # Hello, David!
✅ 最佳实践:
- 应用入口用
asyncio.run(main())- 内部协程互相调用用
await
五、async 的常见使用场景
场景 1:异步 I/O 操作(网络、文件、数据库)
import aiohttp
async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
场景 2:并发执行多个任务
async def main():
urls = ["https://a.com", "https://b.com"]
tasks = [fetch(url) for url in urls]
results = await asyncio.gather(*tasks) # 并发获取
场景 3:异步上下文管理器
async def read_file(path):
async with aiofiles.open(path, 'r') as f: # 异步文件操作
return await f.read()
场景 4:异步生成器(async def + yield)
async def async_range(n):
for i in range(n):
await asyncio.sleep(0.1)
yield i
async def main():
async for x in async_range(3): # 异步迭代
print(x)
六、重要规则与限制
✅ 规则 1:await 只能在 async def 中使用
def bad():
await something() # ❌ SyntaxError!
✅ 规则 2:async def 函数必须被正确执行
# 错误:创建了协程但没执行
greet("Eve") # 警告:coroutine 'greet' was never awaited
✅ 规则 3:不要在 async def 中调用阻塞函数
async def bad_io():
time.sleep(2) # ❌ 阻塞整个事件循环!
async def good_io():
await asyncio.sleep(2) # ✅ 非阻塞
七、async 修饰的其他对象(进阶)
除了函数,async 还可用于:
1. 异步上下文管理器(__aenter__, __aexit__)
class AsyncResource:
async def __aenter__(self):
print("Acquiring resource")
return self
async def __aexit__(self, *args):
print("Releasing resource")
async def main():
async with AsyncResource() as res: # ✅
pass
2. 异步迭代器(__aiter__, __anext__)
class AsyncCounter:
def __init__(self, n):
self.n = n
self.i = 0
def __aiter__(self):
return self
async def __anext__(self):
if self.i < self.n:
await asyncio.sleep(0.1)
self.i += 1
return self.i
raise StopAsyncIteration
async def main():
async for x in AsyncCounter(3): # ✅
print(x)
八、常见误区澄清
❌ 误区 1:“加了 async 就变快了”
✅ 正确:async 本身不加速,只有配合异步 I/O 和并发才能提升吞吐量。
❌ 误区 2:“async def 函数会自动并发执行”
✅ 正确:必须用 create_task() 或 gather() 显式并发,否则仍是顺序执行。
❌ 误区 3:“async/await 是多线程”
✅ 正确:默认是单线程事件循环,通过协作式多任务实现并发。
九、总结:async 的本质
全屏复制
| 问题 | 答案 |
|---|---|
async 作用? | 定义可暂停/恢复的协程函数 |
| 如何使用? | async def func(): ... |
| 调用后发生什么? | 返回协程对象,需 await 或事件循环执行 |
| 必须搭配什么? | 通常搭配 await 使用 |
| 适用场景? | I/O 密集型任务(网络、文件、DB) |
💡 终极口诀:
“async定义暂停点,await触发执行流;
单线程高并发,I/O 等待不再愁。”
掌握 async,你就掌握了 Python 异步编程的第一把钥匙!
更多推荐
所有评论(0)