如何在JMeter中使用并行/吞吐量控制器迭代多参数请求?
JMeter大参数列表迭代优化方案
问题背景
此前通过JSR223后置处理器生成三个参数列表,代码如下:
def imgUIDArrayList = vars.getObject("imageUIDListVal"); def fileListArrayList = vars.getObject("fileListVal"); def filePathListArrayList = vars.getObject("filePathListVal"); 1.upto(imgUIDArrayList.size(),{ vars.put('imageUUIDA_' + it, imgUIDArrayList.get(it - 1))}) 1.upto(fileListArrayList.size(), { vars.put('fileUUIDA_' + it, fileListArrayList.get(it - 1))}) 1.upto(filePathListArrayList.size(), { vars.put('filePathUUIDA_' + it, filePathListArrayList.get(it - 1))})
使用ForEach控制器迭代调用API时,参数列表规模小(如10个)时正常,但规模超过100甚至1000时,单用户执行时长超30分钟,并发时耗时进一步增加,而实际API本身无此性能问题。
当前ForEach控制器配置:
控制器内通过以下方式调用另外两个变量:
${__V(fileUUIDA_${__counter(,)})}vars.get('filePathUUIDA_' + ((vars.get('__jm__ForEach Controller__idx') as int) + 1))
现需解决:如何用Parallel Controller或Throughput Controller实现对应次数的请求迭代?或是否有更优方案?
最优方案:JSR223采样器异步批量请求
ForEach控制器是串行迭代,每个请求必须等待上一个完成,这是性能瓶颈的核心原因。直接用JSR223采样器发起异步HTTP请求,能最大化利用API的并行处理能力,步骤如下:
- 添加JSR223采样器,选择Groovy语言
- 写入以下代码(替换你的API地址、请求方法、参数模板):
import org.apache.http.client.methods.HttpPost import org.apache.http.entity.StringEntity import org.apache.http.impl.client.CloseableHttpClient import org.apache.http.impl.client.HttpClients import org.apache.http.util.EntityUtils // 直接获取原始列表,避免拆分变量的开销 def imgUIDs = vars.getObject("imageUIDListVal") def fileUUIDs = vars.getObject("fileListVal") def filePaths = vars.getObject("filePathListVal") // 创建可复用的HTTP客户端 CloseableHttpClient client = HttpClients.createDefault() def futures = [] // 异步遍历所有参数组合发起请求 imgUIDs.eachWithIndex { imgUID, index -> def fileUUID = fileUUIDs[index] def filePath = filePaths[index] // 构造请求(按需修改请求方法、头、体) HttpPost post = new HttpPost("你的目标API地址") post.setHeader("Content-Type", "application/json") def requestBody = """{"imageUID":"${imgUID}", "fileUUID":"${fileUUID}", "filePath":"${filePath}"}""" post.setEntity(new StringEntity(requestBody)) // 异步执行并收集结果 futures << client.executeAsync(post, { response -> def statusCode = response.getStatusLine().getStatusCode() log.info("请求完成,状态码: ${statusCode}") EntityUtils.consume(response.getEntity()) // 释放资源 }) } // 等待所有请求完成 futures.each { it.get() } client.close()
该方案跳过JMeter控制器的串行调度开销,直接发起并行请求,性能可接近API本身的处理极限。
Parallel Controller实现方式
Parallel Controller可让内部请求并行执行,结合Loop Controller实现对应次数的迭代:
- 添加Parallel Controller
- 在Parallel Controller内添加Loop Controller,设置循环次数为参数列表长度(动态获取:
${__groovy(vars.getObject("imageUIDListVal").size(),)}) - 在Loop Controller内添加API请求,参数调用方式:
- 用计数器:
${__V(imageUUIDA_${__counter(,)})} - 用Loop内置索引:
vars.get('imageUUIDA_' + ((vars.get('__jm__Loop Controller__idx') as int) + 1))
- 用计数器:
注意:Parallel Controller的并行度受JMeter线程数限制,大列表场景需合理调整线程数,避免压垮目标API。
Throughput Controller实现方式
Throughput Controller主要用于控制请求执行的总次数或比例,仅适合需要限制迭代次数的场景,无法解决串行耗时问题:
- 添加Throughput Controller,选择「Total Executions」模式
- 设置吞吐量为参数列表长度(动态获取:
${__groovy(vars.getObject("imageUIDListVal").size(),)}) - 在控制器内添加API请求,参数调用方式同Loop Controller
该方案仍为串行执行,仅适合不需要优化性能、仅需控制迭代次数的场景。
内容的提问来源于stack exchange,提问作者Jyoti Prakash Mallick
相关产品推荐
相关产品推荐

