写点什么

性能测试中的随机数性能问题探索

作者:FunTester
  • 2022 年 7 月 12 日
  • 本文字数:2160 字

    阅读完需:约 7 分钟

在软件测试中,经常会遇到随机数。我简单分成了两类:


  1. 简单取随机数;

  2. 从一个集合中随机取值。


其实第二个场景包含在第一个场景内。对于接口测试来说,通常我们直接使用第二种场景比较多,就是从某一个集合中随机取一个值。如果更复杂一些,每个值拥有不同的权重,其中这个也可以转化成第二个场景来说。

缘起

为什么要把第二个场景和第一个场景分开呢,这个问题源于之前写过的文章ConcurrentHashMap性能测试,当时发现自己封装的com.funtester.frame.SourceCode#random(java.util.List<F>)方法性能存在瓶颈,特别消耗 CPU 资源。


虽然单机 QPS 也在 50 万+,但是因为这个方法很多地方都会用到,所以还是想提升一些性能。所以我就搜索了一些高性能随机数的功能,跟我之前搜到的资料一致,使用java.util.concurrent.ThreadLocalRandom这个实现类是性能最高的,方法如下:


    /**     * 获取随机数,获取1~num 的数字,包含 num     *     * @param num 随机数上限     * @return 随机数     */    public static int getRandomInt(int num) {        return ThreadLocalRandom.current().nextInt(num) + 1;    }
复制代码


针对第二种场景,还有一种实现思路:通过循环去集合中取即可。就是顺序去取,而不是每次都从集合中随机。


举个例子,我们有 10 万测试用户进行流量回放,演示代码如下:


        def funtest = {            random(drivers).getGetResponse(random(urls))        }        new FunQpsConcurrent(funtest).start()
复制代码


这里调用了两次com.funtester.frame.SourceCode#random(java.util.List<F>),当 QPS 到达 10 万级别时候,理论上这个方法导致的瓶颈还是有一些影响的。

多线程

所以我用了新思路进行改造,下面是两种思路的对比压测用例,这个测试用例里面其实有三个实现:


  1. random

  2. AtomicInteger

  3. int


用例如下:


package com.funtest.groovytest
import com.funtester.base.constaint.FixedThreadimport com.funtester.frame.SourceCodeimport com.funtester.frame.execute.Concurrent
import java.util.concurrent.atomic.AtomicInteger
class FunTest extends SourceCode {
static int times = 1000
static int thread = 500
static def integers = 0..100 as List
static def integer = new AtomicInteger()
static def i = 0
static def size = integers.size()
public static void main(String[] args) { RUNUP_TIME = 0 new Concurrent(new FunTester(), thread, "测试随机数性能").start() }
private static class FunTester extends FixedThread {

FunTester() { super(null, times, true) }
@Override protected void doing() throws Exception { 10000.times {random(integers)}// 10000.times {integers.get(integer.getAndIncrement() % size)}// 10000.times {integers.get(i++ % size)} }
@Override FunTester clone() { return new FunTester() } }
}
复制代码


由于测试中均达到了 CPU 硬件瓶颈,相同参数情况下结论比较明显,就没有进行多轮的对比测试。下面分享一下测试结果:


  1. random:1151

  2. AtomicInteger:3152

  3. int:2273


没想到用了java.util.concurrent.atomic.AtomicInteger反而性能更高了,这个问题略微有点深奥,暂时没有思路。

单线程

下面我们来测试一下单线程的性能,下面是我的用例:


package com.funtest.groovytest

import com.funtester.frame.SourceCode
import java.util.concurrent.atomic.AtomicInteger
class FunTestT extends SourceCode {
static int times = 1000000
static def integers = 0..100 as List
static def integer = new AtomicInteger()
static def i = 0
static def size = integers.size()
public static void main(String[] args) {
time { // times.times {random(integers)} // times.times {integers.get(integer.getAndIncrement() % size)} times.times {integers.get(i++ % size)} } , "随机数性能测试"
}

}
复制代码


下面是测试结果,这里我记录了执行完所有循环次数的时间,单位是 ms(毫秒)。


  1. random:763

  2. AtomicInteger:207

  3. int:270


这下结论明确了,就java.util.concurrent.atomic.AtomicInteger了。

末了

最终写了一个新的随机对象的方法:


    /**     * 随机选择某个对象     *     * @param list     * @param index 自增索引     * @param <F>     * @return     */    public static <F> F random(List<F> list, AtomicInteger index) {        if (list == null || list.isEmpty()) ParamException.fail("数组不能为空!");        return list.get(index.getAndIncrement() % list.size());    }
复制代码


BUG 挖掘机·性能征服者·头顶锅盖



阅读原文,跳转我的仓库地址

发布于: 刚刚阅读数: 3
用户头像

FunTester

关注

公众号:FunTester,800篇原创,欢迎关注 2020.10.20 加入

Fun·BUG挖掘机·性能征服者·头顶锅盖·Tester

评论

发布
暂无评论
性能测试中的随机数性能问题探索_FunTester_InfoQ写作社区