.net의 비동기 성능 테스트를 위한 샘플 코드

黄舟
풀어 주다: 2017-09-21 11:35:45
원래의
1498명이 탐색했습니다.

오랫동안 블로그를 작성하지 않았습니다. 올해 제가 일하고 있는 제품 회사에서 얼마 전 기자간담회를 열었습니다. 잠시 시간을 내어 제품의 성능 최적화를 위한 여지가 있는지 생각해 보았습니다. 만들기 때문에 .Net의 비동기식으로 성능을 최적화할 수 있다고 생각했는데, 그 비율을 얼마나 높일 수 있을까요? 친구가 여러 언어로 비동기 성능 테스트를 하고 있는 일이 있어서(비동기와 동기화에 대한 질문은 게스트 "AIO 및 BIO 인터페이스 성능 비교"를 참조하세요) 그래서 오늘 C# 테스트 프로그램을 작성했습니다.

먼저 ASP.NET MVC WebAPI 프로젝트를 빌드하고 기본 컨트롤러 값에 두 가지 메서드를 추가합니다.


 // 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;
        }
로그인 후 복사

그런 다음 이 웹 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;
        }
    }
로그인 후 복사

코드 보기

는 실제로 주로 다음 코드 줄입니다.


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
로그인 후 복사

원래 10,000개의 스레드를 테스트하려고 했는데 오류가 보고되었습니다.

위의 테스트 결과에서는 QPS가 높지 않은 것으로 나타났으나 IISExpress를 사용하고 웹 서버 소프트웨어마다 성능이 다르기 때문에 진행 중인 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;
        }
    }
로그인 후 복사

코드 보기

키 코드에는 다음 두 가지 메서드만 있습니다.


 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 문이 사용됩니다.

다음은 웹이 아닌 프로세스 내 비동기 멀티스레딩 및 동기 멀티스레딩의 결과입니다.


请输入线程数: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 프로그램이 10,000개의 작업을 시작하는 것을 보여줍니다(10,000개의 네이티브 스레드가 아닌 스레드 풀 스레드). 고려해야 함), 비동기 방식의 QPS는 100,000을 초과하는 반면, 동기화 방식의 경우 성능 격차가 여전히 큽니다.

참고: 위 테스트 결과의 테스트 환경은

Intel i7-4790K CPU, 4코어 및 8스레드, 16GB 메모리, Win10 Enterprise Edition

입니다.

위 내용은 .net의 비동기 성능 테스트를 위한 샘플 코드의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿