Maison > développement back-end > Tutoriel C#.Net > Exemple de code pour les tests de performances asynchrones dans .net

Exemple de code pour les tests de performances asynchrones dans .net

黄舟
Libérer: 2017-09-21 11:35:45
original
1508 Les gens l'ont consulté

Cela fait longtemps que je n'ai pas écrit de blog. La société de produits sur laquelle je travaille cette année vient de tenir une conférence de presse ces deux jours-ci. Après un peu de temps libre, je me suis demandé s'il y avait de la place pour l'optimisation des performances. des produits que nous fabriquons, j'ai donc pensé que l'asynchrone de .Net pouvait optimiser les performances, mais dans quelle proportion peut-il être augmenté ? Il arrive qu'un ami effectue des tests de performances asynchrones dans différents langages (pour les questions sur l'asynchrone et la synchronisation, veuillez vous référer à l'invité "Comparaison des performances des interfaces AIO et BIO"), j'ai donc écrit un programme de test C# aujourd'hui.

Tout d'abord, créez un projet WebAPI ASP.NET MVC et ajoutez deux méthodes aux valeurs du contrôleur par défaut :


 // 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;
        }
Copier après la connexion

Ensuite, créez une console programme pour tester cette API web :


 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;
        }
    }
Copier après la connexion

Voir le code

En fait, il s'agit principalement des lignes de code suivantes :


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

Notez que vous devrez peut-être utiliser Nuget pour ajouter le package suivant :

Microsoft.AspNet.WebApi.Client

Enfin, lancez ce test et les résultats sont les suivants :


按任意键开始测试 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
Copier après la connexion

Au départ, je voulais essayer de testez 10 000 threads, mais une erreur a été signalée.

Le QPS des résultats des tests ci-dessus n'est pas élevé, mais comme IISExpress est utilisé, les performances des différents logiciels de serveur Web sont différentes, il est donc nécessaire de comparer le QPS en cours résultats, créez donc un nouveau programme console A avec le code suivant :


 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;
        }
    }
Copier après la connexion

Afficher le code

Notez que le code clé n'a que les deux méthodes suivantes :


 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;
        }
Copier après la connexion

Ces deux méthodes sont les mêmes que le code de la méthode de test WebAPI , mais le code d'appel est légèrement différent :

Appel synchrone :


 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);
Copier après la connexion

Appel asynchrone :


 for (int i = 0; i < TaskNumber; i++)
            {
                Task task = ExecuteAIO(SleepTime);
                taskArr[i] = task;
            }
            Task.WaitAll(taskArr);
Copier après la connexion

Visible, lors des tests ici, les appels synchrones et asynchrones ainsi que le code client utilisent le multithreading. La principale différence est que la méthode asynchrone utilise des instructions async/await.

Voici les résultats du multithreading asynchrone et du multithreading synchrone en cours de processus non 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
Copier après la connexion

Les résultats montrent que le programme .NET démarre 10 000 tâches (et non 10 000 threads natifs, les threads du pool de threads doivent être pris en compte). Le QPS de la méthode asynchrone dépasse 100 000, tandis que le QPS de la méthode synchrone n'est que de plus de 1 000 points. énorme.

Remarque : L'environnement de test pour les résultats des tests ci-dessus est

CPU Intel i7-4790K, 4 cœurs et 8 threads, 16 Go de mémoire, Win10 Enterprise Edition

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal