Python Asyncio异步编程完全指南
Python的asyncio库是现代Python异步编程的核心,掌握它能让你轻松处理高并发场景,大幅提升程序性能。本文将从零开始,带你深入理解异步编程的本质,并通过大量实战案例帮助你真正掌握asyncio。
一、核心概念:什么是异步编程
在深入asyncio之前,我们需要先理解什么是异步编程,以及为什么需要它。
1.1 同步 vs 异步
同步编程是最传统的编程模式:代码一行一行执行,遇到耗时操作(如网络请求、文件读写)时,程序会阻塞等待,直到操作完成才继续执行下一行。这种方式简单直观,但在处理大量IO操作时效率极低。
异步编程则完全不同:当遇到耗时操作时,程序不会傻等,而是先去做别的事情,等操作完成后再回来处理结果。这就像你去餐厅点餐——同步模式下,你点完餐就站在柜台前等,直到餐做好;异步模式下,你点完餐拿个号码牌找位置坐下,该干嘛干嘛,餐好了叫号再去取。
1.2 协程:异步编程的基础单元
协程(Coroutine)是异步编程的核心概念。它是一种轻量级的函数,可以在执行过程中暂停,让出控制权,之后又可以从暂停的地方继续执行。
import asyncio
async def say_hello():
print("开始打招呼")
await asyncio.sleep(1)
print("你好!")
await asyncio.sleep(1)
print("再见!")
asyncio.run(say_hello())
1.3 事件循环:异步编程的引擎
事件循环(Event Loop)是asyncio的核心。它就像一个永不停止的调度员,不断检查有哪些任务可以执行,哪些任务完成了,然后做出相应的调度。
import asyncio
async def task1():
print("任务1开始")
await asyncio.sleep(2)
print("任务1完成")
return "结果1"
async def task2():
print("任务2开始")
await asyncio.sleep(1)
print("任务2完成")
return "结果2"
async def main():
result = await asyncio.gather(task1(), task2())
print(f"所有任务完成: {result}")
asyncio.run(main())
二、核心内容:asyncio核心组件详解
2.1 Task:协程的容器
直接await一个协程是串行执行的。要实现并发,需要把协程包装成Task:
import asyncio
import time
async def download_file(name, delay):
print(f"开始下载 {name}")
await asyncio.sleep(delay)
print(f"{name} 下载完成")
return f"{name} 内容"
async def main():
start = time.time()
task1 = asyncio.create_task(download_file("file1.txt", 2))
task2 = asyncio.create_task(download_file("file2.txt", 1))
result1 = await task1
result2 = await task2
print(f"总耗时: {time.time() - start:.2f}秒")
asyncio.run(main())
2.2 asyncio.gather():批量并发
当需要同时运行多个协程并收集结果时,gather()是最方便的选择:
import asyncio
async def fetch_url(url, delay):
print(f"正在请求 {url}")
await asyncio.sleep(delay)
return f"{url} 的响应数据"
async def main():
urls = ["url1", "url2", "url3"]
tasks = [fetch_url(u, 1) for u in urls]
results = await asyncio.gather(*tasks)
for r in results:
print(r)
asyncio.run(main())
2.3 asyncio.Queue:协程间通信
异步队列是协程之间安全通信的重要工具:
import asyncio
async def producer(queue, pid):
for i in range(5):
await queue.put(f"item-{pid}-{i}")
print(f"生产者{pid} 生产了 item-{pid}-{i}")
await asyncio.sleep(0.1)
async def consumer(queue, cid):
while True:
item = await queue.get()
print(f"消费者{cid} 消费了 {item}")
queue.task_done()
async def main():
q = asyncio.Queue(maxsize=10)
producers = [asyncio.create_task(producer(q, i)) for i in range(2)]
consumers = [asyncio.create_task(consumer(q, i)) for i in range(3)]
await asyncio.gather(*producers)
await q.join()
for c in consumers:
c.cancel()
asyncio.run(main())
三、实战案例:构建高并发爬虫
import asyncio
import aiohttp
import time
async def fetch(session, url, sem):
async with sem:
async with session.get(url) as resp:
return await resp.text()
async def crawl(urls, max_conn=10):
sem = asyncio.Semaphore(max_conn)
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, u, sem) for u in urls]
return await asyncio.gather(*tasks)
async def main():
urls = ["https://httpbin.org/delay/1"] * 5
start = time.time()
await crawl(urls)
print(f"耗时: {time.time()-start:.2f}s")
asyncio.run(main())
四、最佳实践
4.1 避免阻塞事件循环
import asyncio
import time
# 错误:会阻塞事件循环
async def bad():
time.sleep(5) # 不要这样!
# 正确:使用异步sleep
async def good():
await asyncio.sleep(5)
# 如果必须用阻塞函数,放到线程池
async def run_blocking():
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, time.sleep, 5)
4.2 超时处理
import asyncio
async def slow():
await asyncio.sleep(10)
return "完成"
async def main():
try:
r = await asyncio.wait_for(slow(), timeout=3.0)
except asyncio.TimeoutError:
print("超时!")
asyncio.run(main())
总结
Python的asyncio是一个强大而优雅的异步编程框架。通过本文的学习,你应该已经掌握了:
- 核心概念:理解了协程、事件循环、Task等基础概念
- 核心组件:熟练使用gather、wait、Queue等工具
- 实战能力:能够编写高并发爬虫、异步数据库操作
- 最佳实践:避免常见陷阱,编写健壮的异步代码
异步编程的学习曲线确实比同步编程陡峭,但一旦掌握,你会发现它让很多原本复杂的并发问题变得简单优雅。记住:异步不是为了替代同步,而是在合适的场景下提供更高效的解决方案。
本文链接:https://www.kkkliao.cn/?id=841 转载需授权!
版权声明:本文由廖万里的博客发布,如需转载请注明出处。



手机流量卡
免费领卡
号卡合伙人
产品服务
关于本站
