Gatling跨场景存储并复用返回值问题求助
解决Gatling跨场景共享存储值的问题
你的问题核心在于两点:全局变量的线程不安全问题,以及Feeder提前初始化导致无法获取后续生成的ID。咱们一步步拆解解决方案:
原代码的问题分析
- 线程安全隐患:你用了普通的
var l: List[String]来存ID,Gatling是多线程运行场景的,多个用户同时修改这个列表会导致数据混乱,甚至抛出并发修改异常。 - Feeder初始化时机:
ids = l.map(...)是在场景启动前就执行了,此时l是空列表,所以这个Feeder的迭代器根本没有数据,Get场景自然拿不到ID,报"id not found"。 - 另外注意:代码里的中文引号(
“id”)要改成英文双引号("id"),不然会编译报错。
解决方案:用线程安全队列+动态Feeder
我们可以用线程安全的队列来存储ID,同时自定义一个动态Feeder,实时从队列中获取最新的ID,完美解决跨场景共享的问题:
import java.util.concurrent.atomic.AtomicReference import scala.collection.mutable.Queue // 用AtomicReference包裹线程安全的队列,支持多生产者(Install场景)和多消费者(Get场景) val sharedIdQueue = new AtomicReference[Queue[String]](Queue.empty) val install = scenario("Install") .during(Configuration.duration) { group("installTest") { exec(testChain.installApplication()) .exec(session => { // 从当前Session中取出ID并修剪 val newId = session("id").as[String].trim // 原子性地将ID加入队列,避免并发问题 sharedIdQueue.updateAndGet(queue => queue.enqueue(newId)) session }) } } val get = scenario("Get") .during(Configuration.duration) { group("getTest") { // 自定义动态Feeder:每次获取Feed时,从队列中取出ID feed(() => { var targetId: Option[String] = None // 如果队列为空,短暂等待后重试,避免空转消耗资源 while (targetId.isEmpty) { // 原子性地取出队列头部的ID,并更新队列(移除已取出的元素) targetId = sharedIdQueue.getAndUpdate(queue => queue.drop(1)).headOption if (targetId.isEmpty) Thread.sleep(100) } // 返回Feeder需要的Map格式 Map("id" -> targetId.get) }) .exec(session => { println(session("id").as[String]) session }) } } setUp( warmupScenario.inject(constantConcurrentUsers(1) during(1)) .andThen(install.inject(nothingFor(10 seconds), rampUsers(Configuration.users) during (Configuration.ramp seconds))) .andThen(get.inject(nothingFor(Configuration.duration seconds), rampUsers(Configuration.users) during (Configuration.ramp seconds))) ) .assertions(details("installTest").successfulRequests.percent.gte(Configuration.passPercentage)) .protocols(HTTP_PROTOCOL)
方案说明
- 线程安全存储:
AtomicReference[Queue[String]]保证了多线程环境下,Install场景的多个用户可以安全地往队列里添加ID,Get场景的用户也能安全地取出ID。 - 动态Feeder:自定义的Feeder是一个函数(
() => Map[String, String]),每次调用时都会实时从队列中获取最新的ID,彻底解决了Feeder提前初始化的问题。如果队列为空,会短暂等待后重试,确保能拿到ID再继续执行。 - 避免空转:加入
Thread.sleep(100)是为了避免队列为空时,Feeder循环空转消耗CPU资源,你可以根据实际场景调整等待时间。
内容的提问来源于stack exchange,提问作者santosh jk
相关产品推荐
相关产品推荐

