线程和进程是并发执行的两种主要方式
multiprocessing
模块来创建和管理进程。threading
模块来创建和管理线程。import multiprocessing
def worker():
print("Process worker")
if __name__ == "__main__":
p = multiprocessing.Process(target=worker)
p.start()
p.join()
import threading
def worker():
print("Thread worker")
t = threading.Thread(target=worker)
t.start()
t.join()
选择使用进程还是线程,取决于具体的应用场景和需求。
参考1:https://liaoxuefeng.com/books/python/async-io/coroutine/index.html
参考2:https://liaoxuefeng.com/books/python/async-io/asyncio/index.html
协程(Coroutine) 是一种特殊的函数,能够在执行过程中暂停(挂起)并在稍后恢复执行。它是实现异步编程的核心机制之一,常用于处理 I/O 密集型任务(如网络请求、文件读写等),避免阻塞主线程。
协程与普通函数的区别在于:
await
或 yield
),并在适当的时候恢复执行。可暂停和恢复
协程可以在执行过程中暂停,将控制权交还给调用者,稍后再从暂停的地方恢复执行。
异步非阻塞
协程通常与异步 I/O 操作结合使用,避免阻塞主线程,提高程序的并发性能。
轻量级
协程的上下文切换开销比线程小得多,适合高并发场景。
事件循环(Event Loop)
协程的运行依赖于事件循环。事件循环负责调度协程的执行,当协程遇到 await
时,事件循环会暂停当前协程,转而执行其他任务。
挂起和恢复
当协程遇到 await
时,它会挂起自己,并将控制权交还给事件循环。事件循环会在异步操作完成后恢复协程的执行。
协程的实现基于 Python 的生成器(Generator)。生成器通过 yield
关键字实现暂停和恢复,而协程通过 await
实现类似的功能。不过,协程更专注于异步编程,而生成器更常用于惰性计算。
在 Python 中,协程通过 async
和 await
关键字实现:
async def
:定义一个协程函数。await
:暂停协程的执行,等待异步操作完成。import asyncio
async def say_hello():
print("Hello")
await asyncio.sleep(1) # 模拟 I/O 操作,暂停 1 秒
print("World")
# 运行协程
asyncio.run(say_hello())
Hello!
(等待约1秒)
World!
import asyncio
async def io_operation(name, delay):
print(f"IO操作 {name} 开始")
await asyncio.sleep(delay)
print(f"IO操作 {name} 完成")
return f"{name} 的结果"
async def compute_operation(name, delay):
print(f"计算操作 {name} 开始")
await asyncio.sleep(delay) # 模拟耗时计算
print(f"计算操作 {name} 完成")
return f"{name} 的计算结果"
async def network_operation(name, delay):
print(f"网络操作 {name} 开始")
await asyncio.sleep(delay) # 模拟网络请求
print(f"网络操作 {name} 完成")
return f"{name} 的网络响应"
# 设计task中有多个协程
async def task(name, delay):
print(f"Task {name} 启动")
# 并发执行多个异步操作
results = await asyncio.gather(
io_operation(f"{name}-IO", delay),
compute_operation(f"{name}-Compute", delay/2),
network_operation(f"{name}-Network", delay*1.5)
)
# 串行执行一些操作
result2 = await io_operation(f"{name}-Sequential", 10) # delay/3
result3 = await compute_operation(f"{name}-Final", delay/4)
print(f"Task {name} 完成,获得结果:{results}, {result2}, {result3}")
async def main():
# 并发执行多个协程
await asyncio.gather(
task("A", 2),
task("B", 1),
task("C", 3),
)
if __name__ == "__main__":
asyncio.run(main())
Task A 启动
Task B 启动
Task C 启动
IO操作 A-IO 开始
计算操作 A-Compute 开始
网络操作 A-Network 开始
IO操作 B-IO 开始
计算操作 B-Compute 开始
网络操作 B-Network 开始
IO操作 C-IO 开始
计算操作 C-Compute 开始
网络操作 C-Network 开始
计算操作 B-Compute 完成
计算操作 A-Compute 完成
IO操作 B-IO 完成
网络操作 B-Network 完成
计算操作 C-Compute 完成
IO操作 B-Sequential 开始
IO操作 A-IO 完成
网络操作 A-Network 完成
IO操作 C-IO 完成
IO操作 A-Sequential 开始
网络操作 C-Network 完成
IO操作 C-Sequential 开始
IO操作 B-Sequential 完成
计算操作 B-Final 开始
计算操作 B-Final 完成
Task B 完成,获得结果:['B-IO 的结果', 'B-Compute 的计算结果', 'B-Network 的网络响应'], B-Sequential 的结果, B-Final 的计算结果
IO操作 A-Sequential 完成
计算操作 A-Final 开始
计算操作 A-Final 完成
Task A 完成,获得结果:['A-IO 的结果', 'A-Compute 的计算结果', 'A-Network 的网络响应'], A-Sequential 的结果, A-Final 的计算结果
IO操作 C-Sequential 完成
计算操作 C-Final 开始
计算操作 C-Final 完成
Task C 完成,获得结果:['C-IO 的结果', 'C-Compute 的计算结果', 'C-Network 的网络响应'], C-Sequential 的结果, C-Final 的计算结果
async def main():
tasks = [task("A", 2), task("B", 1), task("C", 3)]
for i in range(3):
print(f"Execute Task {i} started")
task_return = asyncio.create_task(tasks[i % len(tasks)])
await asyncio.wait_for(task_return, timeout=300)
print(f"Execute Task {i} completed")
if __name__ == "__main__":
asyncio.run(main())
Execute Task 0 started
Task A 启动
IO操作 A-IO 开始
计算操作 A-Compute 开始
网络操作 A-Network 开始
计算操作 A-Compute 完成
IO操作 A-IO 完成
网络操作 A-Network 完成
IO操作 A-Sequential 开始
IO操作 A-Sequential 完成
计算操作 A-Final 开始
计算操作 A-Final 完成
Task A 完成,获得结果:['A-IO 的结果', 'A-Compute 的计算结果', 'A-Network 的网络响应'], A-Sequential 的结果, A-Final 的计算结果
Execute Task 0 completed
Execute Task 1 started
Task B 启动
IO操作 B-IO 开始
计算操作 B-Compute 开始
网络操作 B-Network 开始
计算操作 B-Compute 完成
IO操作 B-IO 完成
网络操作 B-Network 完成
IO操作 B-Sequential 开始
IO操作 B-Sequential 完成
计算操作 B-Final 开始
计算操作 B-Final 完成
Task B 完成,获得结果:['B-IO 的结果', 'B-Compute 的计算结果', 'B-Network 的网络响应'], B-Sequential 的结果, B-Final 的计算结果
Execute Task 1 completed
Execute Task 2 started
Task C 启动
IO操作 C-IO 开始
计算操作 C-Compute 开始
网络操作 C-Network 开始
计算操作 C-Compute 完成
IO操作 C-IO 完成
网络操作 C-Network 完成
IO操作 C-Sequential 开始
IO操作 C-Sequential 完成
计算操作 C-Final 开始
计算操作 C-Final 完成
Task C 完成,获得结果:['C-IO 的结果', 'C-Compute 的计算结果', 'C-Network 的网络响应'], C-Sequential 的结果, C-Final 的计算结果
Execute Task 2 completed
Agent 的核心功能通常涉及大量 网络请求 和 异步事件处理,例如:
asyncio
的优势:
用单线程即可管理数千个并发连接,避免多线程的上下文切换开销(GIL 限制下,Python 多线程并不适合高并发 I/O)。
Agent 的本质是 响应事件(如用户输入、系统触发、定时任务),而 asyncio
的事件循环机制天然适合这种模式:
典型案例:
一个聊天 Agent 在等待 GPT-4 生成回复时,可以同时处理其他用户的查询,而非阻塞排队。
现代 Python 异步库(如 aiohttp
、asyncpg
、FastAPI
)普遍基于 asyncio
设计。Agent 需要集成这些组件时,asyncio
提供统一接口:
tortoise-orm
)或驱动(如 asyncpg
)。aiohttp
)、WebSocket(websockets
)。aiokafka
)、RabbitMQ(aio-pika
)。Agent 常需处理 流式数据(如逐字输出 LLM 响应、实时日志监控)。asyncio
的异步生成器(async for
)可优雅实现:
async def stream_llm_response(query):
async with aiohttp.ClientSession() as session:
async with session.post("https://api.openai.com/...", json={"query": query}) as resp:
async for chunk in resp.content: # 流式读取
yield chunk.decode()
asyncio
的 Agent 场景multiprocessing
或分离为微服务)。requests
、psycopg2
)会阻塞事件循环,需通过 run_in_executor
隔离。asyncio
?需求 | asyncio 的解决方案 |
---|---|
高并发 I/O | 单线程事件循环 + 协程挂起 |
事件驱动 | 原生支持异步回调与任务调度 |
集成现代异步库 | 生态一致性(HTTP/DB/MQ 等) |
低资源消耗 | 轻量级协程替代线程 |
流式/实时响应 | 异步生成器与 await 非阻塞等待 |
典型案例:
aiohttp
。协程是一种轻量级的并发编程工具,能够暂停和恢复执行,适合处理 I/O 密集型任务和高并发场景。在 Python 中,协程通过 async
和 await
实现,是异步编程的核心机制之一。
∼ O n e p e r s o n g o f a s t e r , a g r o u p o f p e o p l e c a n g o f u r t h e r ∼ \sim_{One\ person\ go\ faster,\ a\ group\ of\ people\ can\ go\ further}\sim ∼One person go faster, a group of people can go further∼