在Python生态中,异步编程已经从边缘技术演变为现代高并发应用的基石。传统同步编程模型在处理I/O密集型任务时,会因阻塞调用导致线程空转,造成资源浪费。而异步编程通过事件循环和协程机制,实现了单线程内的并发执行,使得单个线程可以同时维护成千上万个网络连接。
Python异步编程的发展经历了几个关键阶段:
关键认知:异步编程不是为了让代码跑得更快,而是为了提高资源利用率。当你的应用有大量时间花在等待I/O时(如网络请求、数据库查询),异步模型通常能带来数量级的性能提升。
理解异步编程必须从生成器开始。生成器函数通过yield关键字暂停执行并返回中间结果,其核心是实现了迭代器协议:
python复制def simple_generator():
yield 1
yield 2
yield 3
gen = simple_generator()
print(next(gen)) # 输出1
print(next(gen)) # 输出2
print(next(gen)) # 输出3
print(next(gen)) # 抛出StopIteration
当生成器耗尽时,Python会抛出StopIteration异常。这个看似简单的机制,实际上为协程奠定了基础——通过.send()方法,我们可以在恢复生成器时传入数据:
python复制def coro():
while True:
x = yield
print(f"Received: {x}")
c = coro()
next(c) # 启动生成器(执行到第一个yield)
c.send(10) # 输出"Received: 10"
Python 3.3引入的yield from语法进一步简化了生成器间的委托:
python复制def sub_gen():
yield from range(3)
def main_gen():
yield from sub_gen()
for item in main_gen():
print(item) # 输出0,1,2
这种"子生成器"模式允许将多个生成器组合成执行管道,这正是早期asyncio实现的基础。当与异常处理和返回值结合时,它展现出了完整的协程特性:
python复制def sub_gen():
result = yield from some_async_operation()
return result
Asyncio的核心是事件循环(Event Loop),它负责:
典型的事件循环工作流程:
python复制import asyncio
async def main():
print('Hello')
await asyncio.sleep(1)
print('World')
asyncio.run(main()) # Python 3.7+
在asyncio中,主要有三种可等待对象:
创建Task的几种方式:
python复制# 方式1:显式创建
task = asyncio.create_task(coro())
# 方式2:使用ensure_future
task = asyncio.ensure_future(coro())
# 方式3:事件循环直接创建
task = loop.create_task(coro())
重要区别:直接调用协程函数不会执行代码,它只是返回一个协程对象。只有通过await或将其包装为Task才会真正执行。
对于需要资源清理的场景,asyncio提供了异步上下文管理器:
python复制async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
这等价于:
python复制session = await aiohttp.ClientSession().__aenter__()
try:
response = await session.get(url).__aenter__()
try:
return await response.text()
finally:
await response.__aexit__(None, None, None)
finally:
await session.__aexit__(None, None, None)
当需要限制并发任务数量时,常用的几种方案:
信号量模式
python复制sem = asyncio.Semaphore(10)
async def limited_task():
async with sem:
await do_work()
任务组模式(Python 3.11+)
python复制async with asyncio.TaskGroup() as tg:
for _ in range(100):
tg.create_task(do_work())
队列消费者模式
python复制async def worker(queue):
while True:
item = await queue.get()
try:
await process(item)
finally:
queue.task_done()
queue = asyncio.Queue(maxsize=50)
workers = [asyncio.create_task(worker(queue)) for _ in range(10)]
在GUI应用或现有同步代码中集成asyncio的技巧:
python复制def sync_code():
# 从同步代码运行协程
result = asyncio.run_coroutine_threadsafe(async_func(), loop)
return result.result()
async def async_code():
# 在事件循环线程执行同步函数
result = await loop.run_in_executor(None, blocking_func)
return result
asyncio内置的调试工具:
python复制# 启用调试模式
asyncio.run(main(), debug=True)
# 获取当前运行任务
task = asyncio.current_task()
# 获取所有任务
tasks = asyncio.all_tasks()
性能分析建议:
使用aiohttp构建REST API的模板:
python复制from aiohttp import web
async def handle(request):
name = request.match_info.get('name', "Anonymous")
return web.Response(text=f"Hello, {name}")
app = web.Application()
app.add_routes([
web.get('/', handle),
web.get('/{name}', handle)
])
async def background_task(app):
while True:
await asyncio.sleep(10)
print("Background task running")
app.on_startup.append(lambda a: asyncio.create_task(background_task(a)))
web.run_app(app, port=8080)
异步ORM的使用示例(以SQLAlchemy 1.4+为例):
python复制from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
engine = create_async_engine("postgresql+asyncpg://user:pass@localhost/db")
async def get_users():
async with AsyncSession(engine) as session:
result = await session.execute(select(User))
return result.scalars().all()
使用gRPC的异步客户端:
python复制async with aio.insecure_channel('localhost:50051') as channel:
stub = helloworld_pb2_grpc.GreeterStub(channel)
response = await stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
print(response.message)
错误示例:
python复制async def bad_example():
time.sleep(1) # 同步阻塞调用
正确做法:
python复制async def good_example():
await asyncio.sleep(1) # 异步非阻塞
正确处理任务取消:
python复制async def cancellable():
try:
await long_running_operation()
except asyncio.CancelledError:
await cleanup_resources()
raise
确保资源释放的可靠模式:
python复制async def safe_operation():
resource = acquire()
try:
await do_work(resource)
finally:
release(resource)
通过简单的HTTP服务器基准测试(wrk -t4 -c100 -d10s):
| 框架 | 请求/秒 | 延迟(ms) | 内存(MB) |
|---|---|---|---|
| 同步Flask | 1200 | 83.33 | 45 |
| 异步aiohttp | 9800 | 10.20 | 32 |
| FastAPI(同步) | 3500 | 28.57 | 38 |
| FastAPI(异步) | 9200 | 10.87 | 35 |
测试环境:4核CPU/8GB内存,Python 3.9,本地网络
python复制class EventBus:
def __init__(self):
self._listeners = defaultdict(list)
def subscribe(self, event_type, listener):
self._listeners[event_type].append(listener)
async def publish(self, event_type, *args, **kwargs):
for listener in self._listeners[event_type]:
await listener(*args, **kwargs)
python复制class CircuitBreaker:
def __init__(self, max_failures=3, reset_timeout=30):
self._failures = 0
self._state = 'closed'
async def call(self, func):
if self._state == 'open':
raise CircuitOpenError()
try:
return await func()
except Exception:
self._failures += 1
if self._failures >= self.max_failures:
self._state = 'open'
asyncio.create_task(self._reset_timer())
raise
python复制def async_cache(ttl=60):
def decorator(func):
cache = {}
lock = asyncio.Lock()
async def wrapper(*args):
if args in cache and time.time() - cache[args][1] < ttl:
return cache[args][0]
async with lock:
result = await func(*args)
cache[args] = (result, time.time())
return result
return wrapper
return decorator
规范的异步项目目录结构示例:
code复制project/
├── app/
│ ├── __init__.py
│ ├── main.py # 入口点
│ ├── core/ # 核心逻辑
│ │ ├── services.py # 业务服务
│ │ └── models.py # 数据模型
│ ├── api/ # 接口层
│ │ ├── routes.py
│ │ └── schemas.py
│ └── utils/ # 工具函数
│ ├── database.py
│ └── logging.py
├── tests/
│ ├── unit/
│ └── integration/
├── config.py # 配置
└── requirements.txt
关键实践: