.net异步性能测试(包括ASP.NET MVC WebAPI异步方法)

简介:

很久没有写博客了,今年做的产品公司这两天刚刚开了发布会,稍微清闲下来,想想我们做的产品还有没有性能优化空间,于是想到了.Net的异步可以优化性能,但到底能够提升多大的比例呢?恰好有一个朋友正在做各种语言的异步性能测试(有关异步和同步的问题,请参考客《AIO与BIO接口性能对比》),于是我今天写了一个C#的测试程序。

首先,建一个 ASP.NET MVC WebAPI项目,在默认的控制器 values里面,增加两个方法:

复制代码
 // GET api/values?sleepTime=10
        [HttpGet]
        public async Task<string> ExecuteAIO(int sleepTime)
        {
            await Task.Delay(sleepTime);
            return  "Hello world,"+ sleepTime;
        }

        [HttpGet]
        // GET api/values?sleepTime2=10
        public string ExecuteBIO(int sleepTime2)
        {
            System.Threading.Thread.Sleep(sleepTime2);
            return "Hello world," + sleepTime2;
        }
复制代码

然后,建立一个控制台程序,来测试这个web API:

  View Code

其实主要是下面几行代码:

HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:62219/");
var result = client.GetStringAsync("api/values?sleepTime=" + input).Result;

注意,你可能需要使用Nuget添加下面这个包:

Microsoft.AspNet.WebApi.Client

最后,运行这个测试,结果如下:

复制代码
按任意键开始测试 WebAPI:http://localhost:62219/api/values?sleepTime={int}
请输入线程数:1000
请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:10
Result:"Hello world,10"
1000次 BIO(同步)测试(睡眠10 毫秒):
耗时(秒):1.2860545,QPS:    777.57
1000次 AIO(异步)测试(睡眠10 毫秒):
耗时(秒):0.4895946,QPS:   2042.51
请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:100
Result:"Hello world,100"
1000次 BIO(同步)测试(睡眠100 毫秒):
耗时(秒):8.2769307,QPS:    120.82
1000次 AIO(异步)测试(睡眠100 毫秒):
耗时(秒):0.5435111,QPS:   1839.89
复制代码

本来想尝试测试10000个线程,但报错了。

 

上面的测试结果,QPS并不高,但由于使用的是IISExpress,不同的Web服务器软件性能不相同,所以还得对比下进程内QPS结果,于是新建一个控制台程序,代码如下:

  View Code

注意,关键代码只有下面两个方法:

复制代码
 public static async Task<string> ExecuteAIO(int sleepTime)
        {
            await Task.Delay(sleepTime);
            return "Hello world," + sleepTime;
        }

        public static string ExecuteBIO(int sleepTime2)
        {
            System.Threading.Thread.Sleep(sleepTime2);
            //不能在非异步方法里面使用 Task.Delay,否则可能死锁
            //Task.Delay(sleepTime2).Wait();
            return "Hello world," + sleepTime2;
        }
复制代码

这两个方法跟WebAPI的测试方法代码是一样的,但是调用代码稍微不同:

同步调用:

复制代码
 Task[] taskArr = new Task[TaskNumber];
            for (int i = 0; i < TaskNumber; i++)
            {
                Task task = Task.Run<string>(()=> ExecuteBIO(SleepTime));
                taskArr[i] = task;

            }
            Task.WaitAll(taskArr);
复制代码

异步调用:

复制代码
 for (int i = 0; i < TaskNumber; i++)
            {
                Task task = ExecuteAIO(SleepTime);
                taskArr[i] = task;
            }
            Task.WaitAll(taskArr);
复制代码

可见,这里测试的时候,同步和异步调用,客户端代码都是使用的多线程,主要的区别就是异步方法使用了 async/await 语句。

下面是非Web的进程内异步多线程和同步多线程的结果:

复制代码
请输入线程数:1000
请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:10
Result:Hello world,10
1000次 BIO(同步)测试(睡眠10 毫秒):
耗时(秒):1.3031966,QPS:    767.34
1000次 AIO(异步)测试(睡眠10 毫秒):
耗时(秒):0.026441,QPS:  37820.05
请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:100
Result:Hello world,100
1000次 BIO(同步)测试(睡眠100 毫秒):
耗时(秒):9.8502858,QPS:    101.52
1000次 AIO(异步)测试(睡眠100 毫秒):
耗时(秒):0.1149469,QPS:   8699.67

请输入线程数:10000
请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:10
Result:Hello world,10
10000次 BIO(同步)测试(睡眠10 毫秒):
耗时(秒):7.7966125,QPS:   1282.61
10000次 AIO(异步)测试(睡眠10 毫秒):
耗时(秒):0.083922,QPS: 119158.27
请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:100
Result:Hello world,100
10000次 BIO(同步)测试(睡眠100 毫秒):
耗时(秒):34.3646036,QPS:    291.00
10000次 AIO(异步)测试(睡眠100 毫秒):
耗时(秒):0.1721833,QPS:  58077.64
复制代码

结果表示,.NET程序开启10000个任务(不是10000个原生线程,需要考虑线程池线程),异步方法的QPS超过了10万,而同步方法只有1000多点,性能差距还是很大的。

注:以上测试结果的测试环境是 

Intel i7-4790K CPU,4核8线程,内存 16GB,Win10 企业版

 

总结:

不论是普通程序还是Web程序,使用异步多线程,可以极大的提高系统的吞吐量。

 

后记:

感谢网友“双鱼座” 的提示,我用信号量和都用线程Sleep的方式,对同步和异步方法进行了测试,结果如他所说,TPL异步方式,开销很大,下面是测试数据:

复制代码
使用 semaphoreSlim 的情况:

请输入线程数:1000
请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:10
Result:Hello world,10
1000次 BIO(同步)测试(睡眠10 毫秒):
耗时(秒):1.2486964,QPS:    800.84
1000次 AIO(异步)测试(睡眠10 毫秒):
耗时(秒):10.5259443,QPS:     95.00
请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:100
Result:Hello world,100
1000次 BIO(同步)测试(睡眠100 毫秒):
耗时(秒):12.2754003,QPS:     81.46
1000次 AIO(异步)测试(睡眠100 毫秒):
耗时(秒):100.5308431,QPS:      9.95
请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:1000
Result:Hello world,1000
1000次 BIO(同步)测试(睡眠1000 毫秒):
耗时(秒):54.0055828,QPS:     18.52
1000次 AIO(异步)测试(睡眠1000 毫秒):
耗时(秒):1000.4749124,QPS:      1.00
复制代码

使用线程 Sleep的代码改造:

复制代码
  public static async Task<string> ExecuteAIO(int sleepTime)
        {
            //await Task.Delay(sleepTime);
            //return "Hello world," + sleepTime;
            //await Task.Delay(sleepTime);
            //semaphoreSlim.Wait(sleepTime);
            System.Threading.Thread.Sleep(sleepTime);
            return await Task.FromResult("Hello world," + sleepTime);
        }

        public static string ExecuteBIO(int sleepTime2)
        {
            System.Threading.Thread.Sleep(sleepTime2);
            //semaphoreSlim.Wait(sleepTime2);
            //不能在非异步方法里面使用 Task.Delay,否则可能死锁
            //Task.Delay(sleepTime2).Wait();
            return "Hello world," + sleepTime2;
        }
复制代码

运行结果如下:

复制代码
请输入线程数:1000
请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:10
Result:Hello world,10
1000次 BIO(同步)测试(睡眠10 毫秒):
耗时(秒):1.3099217,QPS:    763.40
1000次 AIO(异步)测试(睡眠10 毫秒):
耗时(秒):10.9869045,QPS:     91.02
请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:100
Result:Hello world,100
1000次 BIO(同步)测试(睡眠100 毫秒):
耗时(秒):8.5861461,QPS:    116.47
1000次 AIO(异步)测试(睡眠100 毫秒):
耗时(秒):100.9829406,QPS:      9.90
请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:1000
Result:Hello world,1000
1000次 BIO(同步)测试(睡眠1000 毫秒):
耗时(秒):27.0158904,QPS:     37.02
1000次 AIO(异步)测试(睡眠1000 毫秒):
复制代码

在每次睡眠1秒的异步方法测试中,很久都没有出来结果,不用考虑,QPS肯定低于一秒了。

经验教训:

在异步方法中,不要使用 Thread.Sleep;在同步方法中,不要使用Task.Delay ,否则可能出现线程死锁,结果难出来。




    本文转自深蓝医生博客园博客,原文链接:http://www.cnblogs.com/bluedoctor/p/7562705.html,如需转载请自行联系原作者


相关实践学习
通过性能测试PTS对云服务器ECS进行规格选择与性能压测
本文为您介绍如何利用性能测试PTS对云服务器ECS进行规格选择与性能压测。
相关文章
|
8天前
|
敏捷开发 测试技术
软件测试中的探索性测试方法
【6月更文挑战第12天】探索性测试,一种灵活的测试实践,旨在通过自由形式的探索发现软件的潜在缺陷。它不依赖于事先编写的测试用例,而是鼓励测试人员利用直觉、经验和创造力来指导测试过程。本文将深入探讨探索性测试的核心概念、实施策略以及它如何增强传统测试方法的有效性。
|
16天前
|
XML 设计模式 Java
PowerMock:静态方法与私有方法测试
PowerMock是Java单元测试中扩展Mockito的框架,允许模拟静态方法、构造函数、私有方法和final类,以增强测试隔离和覆盖率。主要应用场景包括静态方法模拟、私有方法测试和构造函数/Final类模拟。然而,使用时需注意配置复杂性、避免过度使用、精确控制模拟行为和遵循最佳实践。示例展示了如何模拟静态方法,通过添加PowerMock依赖和使用PowerMockito.mockStatic进行静态方法的模拟和验证。正确使用PowerMock能提升测试质量,但应谨慎以保持代码可读性和测试有效性。
PowerMock:静态方法与私有方法测试
|
16天前
|
存储 安全 测试技术
渗透测试之白盒测试:一种深入的安全性评估方法
渗透测试中的白盒测试是一种利用系统详细信息(如源代码、数据库结构和网络拓扑)进行深度安全评估的方法。通过源代码审查、数据库分析和网络拓扑研究,测试人员能更准确地发现漏洞并提高测试效率。尽管白盒测试能深入揭露潜在威胁,但也面临信息获取难、代码理解复杂及对测试人员高技能要求的挑战。
渗透测试之白盒测试:一种深入的安全性评估方法
|
18天前
|
测试技术 UED
课题项目结题测试通常会采用的方法
课题项目结题测试确保项目准确稳定,涉及功能测试、性能测试、安全测试、兼容性测试、用户验收测试及文档审查。这些方法全面评估项目各方面,保证顺利交付和使用,同时促进项目改进。标签:结题测试、软件测试报告。
课题项目结题测试通常会采用的方法
|
20天前
|
运维 安全 网络架构
【计算巢】网络模拟工具:设计与测试网络架构的有效方法
【6月更文挑战第1天】成为网络世界的超级英雄,利用网络模拟工具解决复杂架构难题!此工具提供安全的虚拟环境,允许自由设计和测试网络拓扑,进行性能挑战和压力测试。简单示例代码展示了创建网络拓扑的便捷性,它是网络设计和故障排查的“魔法棒”。无论新手还是专家,都能借助它探索网络的无限可能,开启精彩冒险!快行动起来,你会发现网络世界前所未有的乐趣!
【计算巢】网络模拟工具:设计与测试网络架构的有效方法
|
2天前
|
敏捷开发 运维 Devops
现代软件测试方法与挑战
在当今高度数字化和技术化的时代,软件测试成为保证产品质量和用户体验的关键环节。本文探讨了现代软件测试方法的演进和面临的挑战,从传统到自动化测试的转变,以及如何应对复杂性和快速变化的软件开发环境。
|
2天前
|
敏捷开发 测试技术
软件测试中的探索性测试方法
【6月更文挑战第18天】本文将深入探讨探索性测试(Exploratory Testing)在软件测试领域的重要性与实施策略。不同于传统的脚本化测试,探索性测试强调测试人员的主观能动性和创造性,以真实用户的角度出发,发现那些可能在规范性测试中被忽视的问题。文章首先介绍探索性测试的定义和优势,然后通过案例分析,展示如何有效执行探索性测试,最后讨论其在敏捷开发环境中的适应性以及如何与传统测试方法相结合以提升测试覆盖率和效率。
|
4天前
|
敏捷开发 机器学习/深度学习 人工智能
现代软件测试方法与挑战
随着信息技术的迅猛发展,现代软件测试面临着越来越复杂的挑战。本文探讨了当前流行的软件测试方法及其在应对不断增长的复杂性和新兴技术方面的应用。重点讨论了自动化测试、敏捷开发以及人工智能在软件测试中的应用,以及它们如何改变了测试团队的角色和策略。最后,文章还分析了未来软件测试面临的可能发展趋势和挑战。
|
14天前
|
数据挖掘 测试技术
软件测试的艺术:确保质量的创造性方法
【6月更文挑战第6天】在数字化时代,软件无处不在。它们渗透到我们生活的方方面面,从个人使用到企业运营。然而,随着软件的普及和复杂性的增加,确保其质量和性能变得至关重要。软件测试是这一过程的核心,它不仅是一门科学,更是一种艺术。本文将探讨如何通过创造性的方法来提高软件测试的效率和效果,从而确保最终产品能够满足用户的期望和需求。
|
15天前
|
敏捷开发 搜索推荐 Devops
现代软件测试方法与挑战
传统的软件测试方法在现代软件开发环境下已经面临着诸多挑战,包括复杂的系统架构、快速迭代的开发周期以及高度定制化的需求。本文将探讨现代软件测试所面临的挑战,并介绍一些新的测试方法和工具,以适应不断变化的软件开发环境。
19 1