分享

多线程与并发程序的测试

 IT乐知 2020-07-08

图怪兽_b32ebf01993f5e42891231a33374d1a6_44816

测试是系统开发中的重中之重,而多线程并发的测试则是其中的难点。

并发测试目的

一个功能的实现可以用串行方式也可以用并发方式,并发程序可以用编写串行程序是采用的设计原则和设计模式,同样在串行程序的测试方法也可以用到并发程序的测试中,但是并发程序由于共享数据,所以存在一定程度的不确定性,一些潜在错误的发生并不具有确定下,而是随机发生的。

并发测试主要分两个方向:安全性测试与活跃性测试。其中安全性测试是为了保证程序不发生任务错误的行为;比如集合的size与真实存储的元素数量是否一致。

活跃性测试则是希望程序能够良好的运行,更多考量是在于性能方面,而在性能测试的衡量标准主要有以下3个方面

吞吐量:一组并发任务中已完成任务所占的比例;

响应性:指请求从发出到完成之间的时间(延迟);

可伸缩性:在增加资源比如CPU情况下,吞吐量提升情况;

并发测试手段

并发程序的测试与串行程序测试需要测试的点会更多,首先是与串行程序一样要有基本的测试,保证程序的基本正确性,主要是保证不变性条件和后验条件,比如前面提到的集合的size与真实存储的数量是否相同这类不变性条件。

在保存程序的基本正确性后就要保证并发方面的问题,首先是阻塞操作的测试,对于共享数据的获取是否有正常的阻塞,还有比如生产者-消费者模式当队列中没有元素时,程序时处于空循环状态还是处于阻塞状态!

最重要的一项就是安全性测试,并发比串行程序最不一样的地方,也是最难以测试准确的地方,多线程测试主要保证提供的是不是多线程测试,创建多个线程去执行测试可能程序并不一定是多线程状态,测试代码执行过程中首先创建的代码说不定已经执行完成了,而后面的线程还没有创建。可以通过栅栏实现在所有线程都准备好的时候在一起执行,来保证真正的并发执行。

即使保证了并发测试也不一定会发现问题,并发出现安全性问题有一定的随机性,也许前面几次程序都不会出现问题,只有通过尽可能多的重复测试,即使这样这可能也只是保证有更高的安全性,并不能保证安全。

并发程序的测试还有一些其他需要测试的地方,比如防止资源耗尽、使用回调可以在合适的位置及时验证数据的不变性,通过在代码层面上修改使并发程序产生更多的交替操作:并发与串行的发生不一样的错误就在于多个线程的交替操作,所以可以在程序中创造更多的交替操作来测试,比如sleep,yield。

性能测试

并发程序最主要解决的一个问题就是解决性能问题,所以性能测试也是并发程序重点之一,性能测试是在基于上一节测试的基础上进行的测试,是为了保证程序在端到端的性能,同时可以根据测试来调整一些参数,找到合适的配置参数组合,使程序能够在系统上良好的运行。

性能测试最主要的指标在于响应时间,如何保证在并发情况下统计准确的响应时间,要保证并发同时还要计算出正确的时间。

性能测试陷阱

并发测试在编写出正确的测试代码后测试还是比较简单,只需要对编写的程序多次执行,统计运行时间这类信息进行分析就行,不过有可能会出现一个不一致的情况影响测试结果。

首先是jvm垃圾回收的影响,因为JVM的垃圾回收时间是无法预测的,所以垃圾回收可能会影响性能的测试,主要有两个方法解决解决,一个是设置-verbose:gc打印垃圾回收的日志,判断是否触发了垃圾回收,触发了肯定对性能有影响,就可以舍弃这次测试结果,另外一个方法是确保垃圾回收在测试期间执行多次,这个包含垃圾回收的测试更加符合真实场景,所以更加推荐这个方式。

第二个是动态编译编译的影响,jvm加载一个类最开始是解释执行,当执行某个方法很多次后可能会把方法代码编译成机器代码,代码就从解释执行变成了直接执行,直接执行的效率更高。动态编译过程会消耗资源影响性能,解决方法是测试运行足够长的时间,或者在运行一定时间后在统计。

还有一个情况是虽然是并发程序,如果程序对共享数据的获取时间很短,整个程序的执行时间相对较长,获取共享数据消耗时间所占的总时间比例很小,实际上对共享数据的竞争也比较小,也就是说虽然是并发实际上并发影响却很小。

其他测试方法

测试的目标不是更多的发现错误,而是提高代码能够按照预期方式工作的可信度,所以保证代码质量也算是测试方法,而保证代码质量的方法很多,比如代码审查,代码审查可以让代码编写之外的人来仔细的检查代码,也能够发现并且完善代码。

并且现在市面上已经有很多的代码质量检查工具了,通过工具能及时的发现代码的各个方面的问题。

现在还有一些分析检测系统正在运行的工具,它可以分析正在运行的程序内部状态的,通过分析状态也能够及时发现问题。

总结

并发程序面对的可能性要多得多,因此测试要比串行程序复杂的多,不仅和串行程序一样要保证不变性条件和后验条件,同时也要保证安全问题,在这些基础上还要保证并发程序的特性吞吐量、响应能力、可伸缩,多线程还涉及到性能问题,这些都是需要测试验证。

在保证这些并发程序基本特性上,还要小心因为多线程导致的其他问题比如资源耗尽、死锁等问题。

Java程序员日常学习笔记,如理解有误欢迎各位交流讨论!

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多