Python 的异步编程主要是通过 asyncio
库来实现,它允许你编写并发代码,以便在等待 I/O 操作(如网络请求、文件读写等)时不阻塞其他任务。异步编程的核心概念包括 协程 (coroutine) 和 事件循环 (event loop),它们让你能够在一个线程中执行多个任务,而不会因为一个任务等待 I/O 而阻塞整个程序。
以下是 Python 异步编程的关键点和示例:
1. 协程 (Coroutine)
协程是可以暂停和恢复的函数。Python 使用 async def
定义协程,协程的执行需要 await
来等待异步操作完成。
import asyncio
async def hello_world():
print("Hello")
await asyncio.sleep(1) # 模拟 I/O 操作,例如网络请求或文件读写
print("World")
# 运行协程
asyncio.run(hello_world())
2. await
关键字
await
用于等待一个异步操作完成,它只能在 async def
定义的协程中使用。await
后面的表达式必须是一个可等待对象,如协程、Future
或 Task
。
3. 事件循环 (Event Loop)
事件循环是异步编程的核心,它负责管理和调度协程的执行。在异步程序中,事件循环负责在协程被挂起等待 I/O 操作时切换到其他任务,以便最大化资源利用。
asyncio.run()
函数就是一个简单的事件循环的例子,它用来启动一个协程并运行它直到完成。
async def main():
print("Start")
await asyncio.sleep(1)
print("End")
asyncio.run(main()) # 运行事件循环
4. 并发任务
通过 asyncio.gather()
或 asyncio.create_task()
,你可以并发地运行多个任务。例如:
import asyncio
async def task1():
await asyncio.sleep(2)
print("Task 1 complete")
async def task2():
await asyncio.sleep(1)
print("Task 2 complete")
async def main():
# 并发运行 task1 和 task2
await asyncio.gather(task1(), task2())
asyncio.run(main())
在这个例子中,task1
和 task2
是并发执行的,而不是顺序执行,整个运行时间将是 2 秒而不是 3 秒。
5. asyncio.create_task()
asyncio.create_task()
创建一个新的任务(Task)并将其添加到事件循环中。任务是对协程的封装,它使得协程可以异步运行,并且可以使用 await
获取其结果。
import asyncio
async def task1():
await asyncio.sleep(1)
print("Task 1 done")
async def task2():
await asyncio.sleep(2)
print("Task 2 done")
async def main():
# 使用 create_task 让 task1 和 task2 并发执行
task_1 = asyncio.create_task(task1())
task_2 = asyncio.create_task(task2())
# 等待所有任务完成
await task_1
await task_2
asyncio.run(main())
6. 超时控制
可以通过 asyncio.wait_for()
来设置协程的超时时间:
import asyncio
async def long_task():
await asyncio.sleep(5)
return "Task completed"
async def main():
try:
# 等待任务完成,最多等待 2 秒
result = await asyncio.wait_for(long_task(), timeout=2)
print(result)
except asyncio.TimeoutError:
print("Task timed out")
asyncio.run(main())
在这个示例中,如果 long_task
在 2 秒内没有完成,程序会抛出 TimeoutError
。
7. 同步和异步代码的混合
虽然异步编程专注于并发操作,但在某些场景下可能需要混合使用同步代码。可以在异步函数中调用同步代码,不过同步代码会阻塞事件循环。因此,在这种情况下,建议将阻塞的同步操作转移到线程池或进程池中。
import asyncio
import time
# 模拟耗时的同步操作
def blocking_task():
time.sleep(3)
print("Blocking task done")
async def main():
print("Start blocking task in thread")
loop = asyncio.get_running_loop()
await loop.run_in_executor(None, blocking_task) # 在线程池中运行同步任务
print("Continue with async code")
asyncio.run(main())
8. 异步 I/O 操作
异步编程非常适合处理 I/O 密集型任务(如网络通信、文件读写等)。常见的异步库有:
- aiohttp: 用于异步 HTTP 请求
- aiomysql / aiopg: 用于异步数据库操作
例如,使用 aiohttp
进行异步 HTTP 请求:
import aiohttp
import asyncio
async def fetch_url(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
async def main():
url = "https://www.example.com"
html = await fetch_url(url)
print(html)
asyncio.run(main())
总结
Python 的异步编程通过 asyncio
提供了简单且高效的并发模型,适合处理 I/O 密集型任务。核心概念包括协程、事件循环和并发任务,通过这些工具可以实现高效的异步程序。