第 4 章 · 任务权重与等待时间
本章目标:精确控制虚拟用户的行为分布——用 @task 权重和 tasks 列表控制任务选择概率,用 between/constant/constant_pacing 三种策略控制执行节奏。
4.1 任务权重的两种写法
装饰器方式
python
from locust import HttpUser, task
class MallUser(HttpUser):
host = "https://httpbin.org"
@task(1)
def view_homepage(self):
self.client.get("/")
@task(3) # 选中概率是上面的 3 倍
def search_product(self):
self.client.get("/get?q=phone")
@task(2)
def add_to_cart(self):
self.client.post("/post", json={"item": "phone", "qty": 1})总权重 = 1+3+2 = 6,各任务被选中概率:首页 16.7%、搜索 50%、购物车 33.3%。
tasks 列表方式
python
class WeightedUser(HttpUser):
host = "https://httpbin.org"
tasks = {view_homepage: 1, search_product: 3} # 字典 {方法: 权重}也可以用列表表示重复次数(等价于权重):
python
tasks = [search_product] * 3 + [view_homepage]两种方式效果相同,装饰器更直观、字典更适合动态场景。
4.2 三种等待时间策略
wait_time 决定了任务之间的停顿,直接决定 RPS 的计算模型:
python
from locust import HttpUser, task, between, constant, constant_pacing
class WaitStrategies(HttpUser):
host = "https://httpbin.org"
# 策略一:随机区间(最常用)
wait_time = between(1, 5)
@task
def demo(self):
self.client.get("/get")| 策略 | 写法 | 行为 |
|---|---|---|
between(a, b) | 每次随机等 a~b 秒 | 最接近真实人类行为 |
constant(t) | 固定等 t 秒 | 简单可控 |
constant_pacing(t) | 任务每 t 秒运行一次(含执行时间) | 精确控制迭代速率 |
constant vs constant_pacing 的区别
这是最容易混淆的一对:
python
# constant(3):任务执行完后固定再等 3 秒
# 如果任务耗时 2s,实际周期 = 2 + 3 = 5s
wait_time = constant(3)
# constant_pacing(3):保证每 3 秒启动一次新迭代
# 如果任务耗时 2s,只额外等待 1s;如果任务耗时 4s,则不等待直接开始下一轮
wait_time = constant_pacing(3)什么时候用 constant_pacing
当你需要精确的 RPS 目标时选它。比如目标 RPS=100,有 50 个并发用户,那么每个用户的 pacing 应设为 50÷100 = 0.5 秒。constant_pacing 会自动补偿任务执行时间的波动。
4.3 SequentialTaskSet:顺序执行的任务组
默认情况下任务是随机选择的。如果需要按顺序执行一组操作(如完整的下单流程),用 SequentialTaskSet:
python
from locust import HttpUser, SequentialTaskSet, task
class CheckoutFlow(SequentialTaskSet):
"""模拟完整购物流程:浏览 → 加购 → 结算"""
@task
def browse(self):
self.client.get("/get")
@task
def add_cart(self):
self.client.post("/post", json={"action": "add_to_cart"})
@task
def pay(self):
self.client.post("/post", json={"action": "pay"})
class ShoppingUser(HttpUser):
host = "https://httpbin.org"
tasks = {CheckoutFlow: 1}
wait_time = between(2, 5)SequentialTaskSet 内部的任务按声明顺序依次执行,走完一轮后重新从头开始。它本身也可以被赋予权重,与其他 TaskSet 或普通任务混合使用。
4.4 组织最佳实践
真实项目的压测脚本往往包含数十个接口。推荐的目录结构:
text
loadtests/
├── locustfile.py # 入口:User 定义 + TaskSet 组合
├── flows/
│ ├── browse.py # 浏览流程
│ ├── checkout.py # 下单流程
│ └── admin.py # 后台操作
└── config/
└── users.py # 测试账号池核心原则:
- 一个"业务流"封装为一个
TaskSet或SequentialTaskSet; - User 类只负责组合这些流并分配权重;
- 公共逻辑(登录、清理)放在基类或 Mixin 中复用。
本章小结
@task(N)和tasks = {method: weight}两种方式控制任务概率;between随机停顿最像真人;constant_pacing能补偿执行时间波动,适合精确 RPS 场景;SequentialTaskSet强制顺序执行,用于不可乱序的业务流(如先加购后结算);- 复杂项目按业务流拆分文件,User 类只做组合。
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. @task(5) 与 @task(1) 的选中概率之比是?
2. constant_pacing(5) 与 constant(5) 的本质区别是什么?
3. 以下哪个场景最适合用 SequentialTaskSet?
4. 目标 RPS 为 200,计划用 100 个并发用户达成,每个用户的 constant_pacing 应设为?
🛠️ 动手实践
- 编写一个包含 3 个任务(权重分别为 10%、60%、30%)的用户类,跑 30 秒后在 Web UI 统计表中验证请求比例是否符合预期。
- 分别用
constant(2)和constant_pacing(2)各跑一次(目标接口/delay/1),对比两者的实际 RPS 差异并解释原因。 - 用
SequentialTaskSet实现"注册 → 登录 → 注销"三步流程,并在每步之间加入 1 秒停顿。
完成后进入第 5 章。