.net中关于异步性能测试的示例代码

.net中关于异步性能测试的示例代码,第1张

概述.net中关于异步性能测试的示例代码 很久没有写博客了,今年做的产品公司这两天刚刚开了发布会,稍微清闲下来,想想我们做的产品还有没有性能优化空间,于是想到了.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:


 class Program    {        static voID Main(string[] args)        {            Console.Writeline("按任意键开始测试 WebAPI:http://localhost:62219/API/values?sleepTime={int}");            Console.Write("请输入线程数:");                        int threadNum = 100;                        int.TryParse(Console.Readline(), out threadNum);                        while (Test(threadNum)) ;            Console.Readline();            Console.Readline();        }        private static bool Test(int TaskNumber)        {            Console.Write("请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:");                        string input = Console.Readline();                        int SleepTime = 50;                        if (!int.TryParse(input, out SleepTime))                            return false;            httpClIEnt clIEnt = new httpClIEnt();            clIEnt.BaseAddress = new Uri("http://localhost:62219/");                        var result = clIEnt.GetStringAsync("API/values?sleepTime=" + input).Result;            Console.Writeline("Result:{0}", result);                        //int TaskNumber = 1000;            Console.Writeline("{0}次 BIO(同步)测试(睡眠{1} 毫秒):", TaskNumber, SleepTime);            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();            sw.Start();            Task[] taskArr = new Task[TaskNumber];                        for (int i = 0; i < TaskNumber; i++)            {                Task task = clIEnt.GetStringAsync("API/values?sleepTime2=" + SleepTime);                taskArr[i] = task;            }            Task.WaitAll(taskArr);            sw.Stop();                        double useTime1 = sw.Elapsed.TotalSeconds;            Console.Writeline("耗时(秒):{0},QPS:{1,10:f2}", useTime1, TaskNumber/useTime1);            sw.reset();            Console.Writeline("{0}次 AIO(异步)测试(睡眠{1} 毫秒):", TaskNumber, SleepTime);            sw.Start();                        for (int i = 0; i < TaskNumber; i++)            {                Task task = clIEnt.GetStringAsync("API/values?sleepTime=" + SleepTime);                taskArr[i] = task;            }            Task.WaitAll(taskArr);            sw.Stop();                        double useTime2 = sw.Elapsed.TotalSeconds;            Console.Writeline("耗时(秒):{0},QPS:{1,10:f2}", useTime2, TaskNumber / useTime2);                        return true;        }    }

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方法的睡眠时间(毫秒),输入非数字内容退出:10Result:"Hello world,10"1000次 BIO(同步)测试(睡眠10 毫秒):耗时(秒):1.2860545,QPS:    777.571000次 AIO(异步)测试(睡眠10 毫秒):耗时(秒):0.4895946,QPS:   2042.51请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:100Result:"Hello world,100"1000次 BIO(同步)测试(睡眠100 毫秒):耗时(秒):8.2769307,QPS:    120.821000次 AIO(异步)测试(睡眠100 毫秒):耗时(秒):0.5435111,QPS:   1839.89

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

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


 class Program    {        static voID Main(string[] args)        {            Console.Writeline("按任意键开始测试 ");            Console.Write("请输入线程数:");                        int threadNum = 100;                        int.TryParse(Console.Readline(), out threadNum);                        while (Test(threadNum)) ;            Console.Readline();            Console.Readline();        }        private static bool Test(int TaskNumber)        {            Console.Write("请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:");                        string input = Console.Readline();                        int SleepTime = 50;                        if (!int.TryParse(input, out SleepTime))                            return false;                        var result = ExecuteAIO(SleepTime).Result;            Console.Writeline("Result:{0}", result);                        //int TaskNumber = 1000;            Console.Writeline("{0}次 BIO(同步)测试(睡眠{1} 毫秒):", TaskNumber, SleepTime);            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();            sw.Start();            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);            sw.Stop();            double useTime1 = sw.Elapsed.TotalSeconds;            Console.Writeline("耗时(秒):{0},QPS:{1,10:f2}", useTime1, TaskNumber / useTime1);            sw.reset();            Console.Writeline("{0}次 AIO(异步)测试(睡眠{1} 毫秒):", TaskNumber, SleepTime);            sw.Start();            for (int i = 0; i < TaskNumber; i++)            {                Task task = ExecuteAIO(SleepTime);                taskArr[i] = task;            }            Task.WaitAll(taskArr);            sw.Stop();            double useTime2 = sw.Elapsed.TotalSeconds;            Console.Writeline("耗时(秒):{0},QPS:{1,10:f2}", useTime2, TaskNumber / useTime2);                        return true;        }        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;        }    }

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方法的睡眠时间(毫秒),输入非数字内容退出:10Result:Hello world,101000次 BIO(同步)测试(睡眠10 毫秒):耗时(秒):1.3031966,QPS:    767.341000次 AIO(异步)测试(睡眠10 毫秒):耗时(秒):0.026441,QPS:  37820.05请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:100Result:Hello world,1001000次 BIO(同步)测试(睡眠100 毫秒):耗时(秒):9.8502858,QPS:    101.521000次 AIO(异步)测试(睡眠100 毫秒):耗时(秒):0.1149469,QPS:   8699.67请输入线程数:10000请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:10Result:Hello world,1010000次 BIO(同步)测试(睡眠10 毫秒):耗时(秒):7.7966125,QPS:   1282.6110000次 AIO(异步)测试(睡眠10 毫秒):耗时(秒):0.083922,QPS: 119158.27请输入此API方法的睡眠时间(毫秒),输入非数字内容退出:100Result:Hello world,10010000次 BIO(同步)测试(睡眠100 毫秒):耗时(秒):34.3646036,QPS:    291.0010000次 AIO(异步)测试(睡眠100 毫秒):耗时(秒):0.1721833,QPS:  58077.64

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

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

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

以上是内存溢出为你收集整理的.net中关于异步性能测试的示例代码全部内容,希望文章能够帮你解决.net中关于异步性能测试的示例代码所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1210979.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-04
下一篇 2022-06-04

发表评论

登录后才能评论

评论列表(0条)

保存