Curio异步编程框架入门教程
概述
Curio是一个基于协程的并发系统编程库,它提供了线程、套接字、文件、锁和队列等常见编程抽象。本教程将深入介绍Curio的核心概念和使用方法,帮助开发者快速掌握这一强大的异步编程工具。
快速开始
基本示例
让我们从一个简单的倒计时程序开始:
import curio
async def countdown(n):
while n > 0:
print('T-minus', n)
await curio.sleep(1) # 异步等待1秒
n -= 1
if __name__ == '__main__':
curio.run(countdown, 10)
这个例子展示了Curio的基本工作流程:
- 定义异步函数(协程函数)
- 使用
await
关键字调用异步操作 - 通过
curio.run()
启动事件循环
任务与并发
Curio允许轻松创建并发任务:
async def kid(x, y):
print('开始做作业')
await curio.sleep(1000) # 模拟长时间任务
return x * y
async def parent():
kid_task = await curio.spawn(kid, 37, 42) # 创建子任务
count_task = await curio.spawn(countdown, 10)
await count_task.join() # 等待倒计时任务完成
print("完成了吗?")
result = await kid_task.join() # 等待子任务完成
print("结果:", result)
核心概念
任务管理
Curio提供了强大的任务管理功能:
- 任务创建:使用
curio.spawn()
创建新任务 - 任务等待:使用
task.join()
等待任务完成 - 任务取消:使用
task.cancel()
取消任务
超时与取消
try:
# 设置10秒超时
result = await curio.timeout_after(10, kid_task.join)
except curio.TaskTimeout:
print("时间到了!")
await kid_task.cancel() # 取消任务
被取消的任务可以捕获CancelledError
异常:
async def kid(x, y):
try:
print('开始做作业')
await curio.sleep(1000)
return x * y
except curio.CancelledError:
print("任务被取消了!")
raise
任务组
任务组(TaskGroup)提供了更高级的任务协调机制:
async def parent():
async with curio.TaskGroup(wait=any) as g:
await g.spawn(kid, 37, 42)
await g.spawn(countdown, 10)
if g.result is None:
print("为什么没完成?")
else:
print("结果:", g.result)
任务组特点:
wait=any
:任意任务完成即结束- 自动取消未完成的任务
- 保证没有任务被遗留
高级特性
处理阻塞操作
Curio是协作式调度,长时间CPU操作会阻塞事件循环。解决方案:
- 计算密集型任务:使用
run_in_process
result = await curio.run_in_process(fib, 40)
- I/O密集型任务:使用
run_in_thread
data = await curio.run_in_thread(requests.get, url)
网络编程
简单的echo服务器示例:
async def echo_client(client, addr):
print('来自', addr, '的连接')
async with client.as_stream() as s:
async for line in s:
await s.write(line)
print('连接关闭')
if __name__ == '__main__':
curio.run(tcp_server, '', 25000, echo_client)
任务间通信
使用Queue实现发布-订阅模式:
messages = Queue()
subscribers = set()
async def dispatcher():
while True:
msg = await messages.get()
for q in subscribers:
await q.put(msg)
async def publish(msg):
await messages.put(msg)
async def subscriber(name):
queue = Queue()
subscribers.add(queue)
try:
while True:
msg = await queue.get()
print(name, '收到', msg)
finally:
subscribers.discard(queue)
调试技巧
- 常见错误:忘记使用
await
curio.sleep(1) # 错误!缺少await
- 使用监视器:
curio.run(main, with_monitor=True)
然后在另一个终端运行:
python3 -m curio.monitor
- 获取任务堆栈:
print(task.traceback())
- 调度器跟踪:
from curio.debug import schedtrace
curio.run(main, debug=schedtrace)
最佳实践
- 编程思维:按照线程编程的思路编写代码,但记得添加
await
- I/O操作:所有I/O操作都需要
await
- 阻塞操作:识别潜在的阻塞点,使用
run_in_process
或run_in_thread
- 错误处理:妥善处理取消和超时
- 资源管理:使用
async with
确保资源正确释放
总结
Curio提供了一种简洁而强大的异步编程模型,通过本教程,您应该已经掌握了:
- 基本任务创建和管理
- 超时和取消机制
- 任务组的高级用法
- 处理阻塞操作的方法
- 网络编程基础
- 任务间通信
- 调试技巧
Curio的设计哲学是保持简单和直观,让开发者能够专注于业务逻辑而不是复杂的并发控制。希望本教程能帮助您快速上手Curio,构建高效的异步应用程序。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考