前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >通用池化框架GenericObjectPool性能测试

通用池化框架GenericObjectPool性能测试

作者头像
FunTester
发布2022-07-08 15:15:52
3820
发布2022-07-08 15:15:52
举报
文章被收录于专栏:FunTester

之前写过了- 通用池化框架commons-pool2实践以及通用池化框架实践之GenericKeyedObjectPool。接下来我就对这个池化框架进行性能测试。首先呢就是因为这个池化技术必需要有足够的性能,不然通过池化技术优化的部分,在较高QPS的性能测试中,对象池可能成为本机瓶颈。

硬件软件配置

硬件就是我自己的电脑,型号MacBook Pro (16-inch, 2019),配置6C16G。因为这次测试并没有测试到性能极限,在测试方案设计的前阶段已经有了相对明显的结论了。

软件方面,还是Groovy,默认Java进程启动参数。对象池化的设置后面可以在代码中看到,经过我的测试,只要对象池中还有空闲对象就足够满足当前性能。因为我本次用的是固定线程模型,所以换算过来就是对象数大于线程数即可。

测试前准备

测试分成了两部分:无等待归还对象、有等待归还对象。因为无等待归还对象测试过程中,结论出现的太早也太明显了。

可池化对象

代码语言:javascript
复制
    /**
     * 可池化对象
     */
    private static class FunTesterPooled {

        String name

        int age

    }

池化工场

代码语言:javascript
复制
    /**
     * 池化工厂
     */
    private static class FunFactory extends BasePooledObjectFactory<FunTesterPooled> {


        @Override
        FunTesterPooled create() throws Exception {
            return new FunTesterPooled()
        }

        @Override
        PooledObject<FunTesterPooled> wrap(FunTesterPooled obj) {
            return new DefaultPooledObject<FunTesterPooled>(obj)
        }

        @Override
        void destroyObject(PooledObject<FunTesterPooled> p, DestroyMode destroyMode) throws Exception {
            p.getObject().setName("") //回收资源
            super.destroyObject(p, destroyMode)
        }
    }

对象池

代码语言:javascript
复制
    static def initPool() {
        def config = new GenericObjectPoolConfig<FunTesterPooled>()
        config.setMaxIdle(10)
        config.setMinIdle(2)
        config.setMaxTotal(thread * 2)
        return new GenericObjectPool<FunTesterPooled>(new FunFactory(), config)
    }

性能测试用例

代码语言:javascript
复制
    static GenericObjectPool<FunTesterPooled> pool

    static def desc = "池化框架性能测试"

    static int times = 3000000

    static int thread = 2

    public static void main(String[] args) {
        this.pool = initPool()
        ThreadBase.COUNT = true
        RUNUP_TIME = 0
        def barrier = new CyclicBarrier(thread + 1)
        POOL_SIZE = thread
        def borrows = []
        thread.times {
            fun {
                borrows << pool.borrowObject()
                barrier.await()
            }
        }
        barrier.await()
        borrows.each {
            pool.returnObject(it)
        }
        output("对象创建完毕 创建数量${pool.getNumIdle()}")
        new Concurrent(new FunTester(), thread, desc).start()
        pool.close()
    }

    private static class FunTester extends FixedThread {


        FunTester() {
            super(null, times, true)
        }

        @Override
        protected void doing() throws Exception {
            pool.returnObject(pool.borrowObject())
        }

        @Override
        FunTester clone() {
            return new FunTester()
        }
    }

其中往对象池中添加对象的时候,一开始我思路有点偏,所以想了一个java.util.concurrent.CyclicBarrier的方案。其实我们直接可以使用官方提供的org.apache.commons.pool2.ObjectPool#addObjects方法实现,代码非常简单,一行搞定pool.addObjects(thread)

测试结果

无等待

线程数

执行次数(万)

QPS

1

300

1876172

2

300

1852364

5

300

1533912

10

300

1524538

10

100

1571623

20

100

1568692

可以看出,QPS非常高,足够满足线性能测试需求。

等待

使用了休眠2ms的配置。

线程数

执行次数(k)

单线程QPS

20

10

410

50

10

406

100

5

406

200

2

404

300

2

403

400

2

403

500

2

262

800

2

143

1000

2

114

看来还是有瓶颈,在并发线程超过400多以后,这个平均单线程QPS会下降会多。猜测可能是org.apache.commons.pool2.impl.LinkedBlockingDequejava.util.concurrent.atomic.AtomicLong两个类的性能瓶颈。可以参考之前做过的Java&Go高性能队列之LinkedBlockingQueue性能测试,虽然不一样可以参考。

虽然后面性能有所下降,瓶颈也在10万以上,也算是满足部分性能测试需求吧。后面我对com.funtest.PoolTest#GenericKeyedObjectPool对象池的性能,敬请期待。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-06-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FunTester 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 硬件软件配置
  • 测试前准备
    • 可池化对象
      • 池化工场
        • 对象池
        • 性能测试用例
        • 测试结果
          • 无等待
            • 等待
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档