第 14 章 · asyncio 支持
本章目标:了解 Locust 的 gevent 并发模型与 asyncio 生态的关系,掌握 aiolocust 的用法,并能根据场景选择合适方案。
14.1 Locust 的并发模型:gevent
Locust 的传统并发基于 gevent——一个 Python 协作式并发的库,通过 monkey-patching 将标准库 I/O 操作替换为非阻塞版本。每个虚拟 User 运行在一个 greenlet(轻量级协程)中:
python
# locust 启动时自动执行 monkey-patch
from gevent import monkey
monkey.patch_all() # 替换 socket、time、threading 等模块的阻塞调用
# 此后所有 User 实例运行在 greenlet 中,I/O 等待时自动让出 CPUgevent 方案的优势:对用户代码透明——你写同步代码,Locust 自动实现并发。劣势是 monkey-patching 对 C 扩展库无效(见第 13 章)。
14.2 aiolocust:asyncio 重新设计
aiolocust 是 2026 年发布的 Locust 生态新项目,用 asyncio/aiohttp 全面替代 gevent/requests 技术栈,拥抱现代 Python 异步标准。
bash
pip install aiolocust基本用法:
python
import asyncio
from aiolocust import HttpUser
async def run(user: HttpUser):
async with user.client.get("http://example.com/") as resp:
pass # 处理响应
async with user.client.get("http://example.com/") as resp:
# 额外校验,不只是 HTTP 状态码:
assert "expected text" in await resp.text()
await asyncio.sleep(0.1)项目状态
aiolocust 目前作为独立项目维护,功能比 Locust 主线少(更极简),依赖 OTEL 做可视化分析。未来可能合并进 Locust 或随主版本发布。
14.3 gevent vs asyncio 对比
| 维度 | gevent (Locust) | asyncio (aiolocust) |
|---|---|---|
| 并发模型 | greenlet + monkey-patch | 原生 async/await |
| 学习成本 | 低(写同步代码) | 中(需理解异步编程) |
| C 扩展兼容 | ❌ 无法 patch | ✅ 原生支持 |
| HTTP 客户端 | requests | aiohttp |
| WebSocket | 需额外库 | aiohttp 内置 |
| 生态系统 | 成熟稳定 | 快速发展 |
| 适用场景 | 传统 HTTP API 压测 | 高并发、C 库依赖、WebSocket |
选型决策树
text
你的压测需要什么?
├── 只测 HTTP/HTTPS API → 用 Locust(gevent),生态最成熟
├── 需要 C 扩展库(psycopg2 等) → 考虑 aiolocust
├── 大量 WebSocket 长连接 → aiolocust 或自定义扩展
├── 团队熟悉 asyncio → aiolocust 更自然
└── 需要完整 Web UI 和分布式 → Locust(功能更全)14.4 在 Locust 中混合使用异步代码
即使不用 aiolocust,也可以在 Locust 任务中调用异步函数(如 asyncpg 数据库查询):
python
import asyncio
from locust import User, task, between
class AsyncDbUser(User):
wait_time = between(0.5, 2)
def on_start(self):
"""在事件循环中创建异步任务"""
self.loop = asyncio.new_event_loop()
self.task_thread = threading.Thread(
target=self.loop.run_forever, daemon=True
)
self.task_thread.start()
def _run_async(self, coro):
"""在线程的事件循环中执行协程"""
return asyncio.run_coroutine_threadsafe(coro, self.loop).result()
@task
def query_database(self):
start = time.perf_counter()
result = self._run_async(self._async_query())
elapsed = (time.perf_counter() - start) * 1000
environment.events.request.fire(
request_type="ASYNC-DB", name="query",
response_time=elapsed, response_length=len(str(result)),
exception=None, context={},
)
async def _async_query(self):
# 这里可以用 asyncpg / aiohttp 等 asyncio 库
conn = await asyncpg.connect(dsn="postgresql://localhost/test")
rows = await conn.fetch("SELECT * FROM users LIMIT 10")
await conn.close()
return rows性能注意
run_coroutine_threadsafe 有线程切换开销。如果大量使用此模式,建议直接评估 aiolocust。
本章小结
- Locust 主线基于 gevent,monkey-patching 让同步代码自动获得并发能力;
- aiolocust 用 asyncio/aiohttp 重新实现了 Locust 核心概念,支持 C 扩展库;
- 两者各有优势:gevent 生态成熟、asyncio 更现代化;
- 可通过
run_coroutine_threadsafe在 Locust 中桥接异步库。
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. Locust 传统并发模型基于哪个库?
2. aiolocust 相比传统 Locust 的核心变化是什么?
3. 以下哪种场景最适合选择 aiolocust?
4. 在 Locust 中调用异步函数的正确方式是?
🛠️ 动手实践
- 安装 aiolocust 并编写一个简单的压测脚本,与同场景下的 Locust 脚本对比 RPS 表现。
- 在 Locust 中通过
run_coroutine_threadsafe桥接aiohttp发起请求。 - 写一份选型备忘录:对比 gevent 与 asyncio 在你们团队技术栈中的优劣。
下一章学习将 Locust 作为库嵌入 你自己的 Python 项目和 CI 流水线。