You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Locust中多虚拟用户执行相同POST/PUT操作时如何避免冲突?

Locust虚拟用户写入操作冲突的解决与优化方案

先说说你现有代码的问题

你用了threading.Lock来做同步,但Locust的虚拟用户是基于gevent协程运行的,线程锁对协程完全不起作用,这种写法根本没法避免多个虚拟用户同时执行写入操作的冲突。

实用的冲突避免方案

1. 用gevent锁做协程级同步

既然Locust用gevent,就得用gevent提供的锁来实现协程间的同步,替换掉线程锁:

from locust import HttpUser, task, between
from gevent.lock import Semaphore

class MyUser(HttpUser):
    wait_time = between(1, 5)
    # 用gevent的信号量做全局同步,保证同一时间只有一个用户执行写入操作
    write_lock = Semaphore()  

    @task
    def perform_post(self):
        headers = {"Content-Type": "application/json"}
        payload = {"key": "value"}  
        
        with self.write_lock:
            response = self.client.post("/items", json=payload, headers=headers)
    
    @task
    def perform_put(self):
        headers = {"Content-Type": "application/json"}
        payload = {"key": "updated_value"}  
        item_id = 123  
        
        with self.write_lock:
            response = self.client.put(f"/items/{item_id}", json=payload, headers=headers)

2. 让每个用户操作独立资源(最优方案)

同步锁会压垮性能,毕竟同一时间只能一个用户干活。更好的思路是避免多个用户操作同一个资源:

  • POST操作:每个用户创建自己的资源,拿到返回的ID后,后续PUT就用这个专属ID
  • PUT操作:提前准备一批独立的资源ID,分配给不同用户,或者让用户只修改自己创建的资源

示例代码:

from locust import HttpUser, task, between

class MyUser(HttpUser):
    wait_time = between(1, 5)
    # 每个用户维护自己的资源ID,避免全局冲突
    user_item_id = None  

    @task(3)  # 调高POST权重,先创建资源
    def create_item(self):
        headers = {"Content-Type": "application/json"}
        payload = {"key": f"user_{self.id}_value"}  # 用用户ID做唯一标识
        response = self.client.post("/items", json=payload, headers=headers)
        
        if response.status_code == 201:
            # 从响应中获取自己创建的资源ID
            self.user_item_id = response.json().get("id")

    @task(1)
    def update_my_item(self):
        if not self.user_item_id:
            return  # 还没创建资源就跳过
        
        headers = {"Content-Type": "application/json"}
        payload = {"key": f"updated_user_{self.id}_value"}
        
        # 只修改自己创建的资源,完全不需要锁
        response = self.client.put(f"/items/{self.user_item_id}", json=payload, headers=headers)

3. 服务端层面的兜底处理

不管客户端怎么优化,服务端都得做幂等性和冲突处理:

  • 用乐观锁:给资源加版本号,更新时带上版本号,版本不匹配就拒绝请求
  • 用ETag:请求头带上If-Match,服务端校验ETag一致才允许更新
  • 设计幂等接口:比如POST用唯一请求ID,重复请求不会重复创建资源

总结

优先选「每个用户操作独立资源」的方案,既不影响性能,又从根源避免冲突;如果必须操作共享资源,就用gevent的锁做协程同步;最后一定要配合服务端的冲突处理机制,确保数据一致性。

内容的提问来源于stack exchange,提问作者john gomez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 01:46:31