开发者社区> 橘子红了呐> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

.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,如需转载请自行联系原作者


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
API参考—实例管理—DescribeDBInstances
调用DescribeDBInstances接口查看实例列表详情。
17 0
API参考—实例管理—DeleteDBInstance
调用DeleteDBInstance接口释放实例。
19 0
PolarDB-X 1.0-API参考-1.0(2017版本)-OpenAPI使用-签名机制
关于 Access Key ID 与 Access Key Secret PolarDB-X 服务会对每个 API 的调用请求进行身份验证,所以无论使用 HTTP 还是 HTTPS 协议提交请求,都需要在请求中包含由 Access Key ID 与 Access Key Secret 所产生的签名(Signature)信息。 Access Key ID 和 Access Key Secret 由阿里云官方颁发给访问者(可以通过阿里云官方网站申请和管理),其中 Access Key ID 用于标识访问者的身份。 Access Key Secret 是用于加密签名字符串和服务器端验证签名字符串
56 0
PolarDB-X 1.0-API参考-1.0(2017版本)-OpenAPI使用-公共参数
公共参数包括两个部分:公共请求参数与公共返回参数。 公共请求参数:每个接口都需要使用的请求参数。 公共返回参数:任何的接口调用,无论成功与否,系统都会返回的参数。
35 0
PolarDB-X 1.0-API参考-1.0(2017版本)-OpenAPI使用-SDK 说明
PolarDB-X OpenAPI SDK 依赖于阿里云的 aliyun-java-sdk-core。所以,使用 PolarDB-X OpenAPI 需要另外引入对 aliyun-java-sdk-core 的依赖。
66 0
PolarDB-X 1.0-API参考-1.0(2017版本)-OpenAPI使用-资源授权
PolarDB-X OpenAPI 的一部分操作(例如创建数据库)依赖 RDS 的 OpenAPI 接口。所以,为确保 PolarDB-X 控制台有权限操作用户的 RDS 资源,PolarDB-X OpenAPI 的使用者要通过 RAM 服务给 PolarDB-X 控制台授权 RDS 资源的访问权限。不然,调用 PolarDB-X OpenAPI 会出现权限不足而报错。
42 0
PolarDB-X 1.0-API参考-1.0(2017版本)-OpenAPI简介
本文介绍 PolarDB-X OpenAPI 的基本概念,包括适用场景、基本原理、功能以及局限性。
66 0
PolarDB-X 1.0-API参考-1.0(2019版本)-其它-ModifyDrdsIpWhiteList
调用ModifyDrdsIpWhiteList接口修改数据库白名单。
37 0
3402
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载
低代码开发师(初级)实战教程
立即下载