CPU 100% 問題分析,我們把博客園踩過的坑又踩了一遍《二》(補充)


問題如下:

針對.net core 異常奇怪問題分析

1、StackExchange.Redis.RedisConnectionException: It was not possible to connect to the redis server(s); to create a disconnected multiplexer, disable AbortOnConnectFail. Timeout
at StackExchange.Redis.ConnectionMultiplexer.ConnectImpl(Func`1 multiplexerFactory, TextWriter log)

2、There is already an open DataReader associated with this Command which must be closed first

3、A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext, however instance members are not guaranteed to be

static void Main(string[] args)
        {
          //按鍵后開始執行
            Console.ReadKey();
            //模擬並發
            while (true)
            {
                Task.Run(Producer);
                Thread.Sleep(200);
            }
           
        }
        /// <summary>
        /// 如果處理程序耗時>請求耗時,也就是說引起並發,就會導致死鎖
        /// </summary>
        static void Producer()
        {
            var result = Process().Result;
            //或者
            //Process().Wait();
        }


        static async Task<bool> Process()
        {
            Console.WriteLine("Start - " + DateTime.Now.ToLongTimeString());
            await Task.Run(() =>
            {
                //模擬任務執行耗時
                Thread.Sleep(1000);
            });

            Console.WriteLine("Ended - " + DateTime.Now.ToLongTimeString());
            return true;
        }        

 

執行效果:

以上可看出:

1、控制台執行5-10個任務后,不再執行Ended 語句的任何內容(Ended語句全部被阻塞)

2、內存占用穩步上升

3、AsyncTest.exe 線程每秒增加一個

 

解決方案:

var result = Process().ConfigureAwait(false);

或修改為異步方法(強烈推薦

     static async Task Producer()
        {
            await Process();
        }

 ---補充 2021.2.26-------------------

優化代碼后進一步測試

測試代碼如下:

  1 using System;
  2 using System.Threading;
  3 using System.Threading.Tasks;
  4 
  5 namespace AsyncTest
  6 {
  7     class Program
  8     {
  9         static void Main(string[] args)
 10         {
 11             Console.ReadKey();
 12             //模擬並發
 13             for (int i = 0; i < 300; i++)
 14             {
 15                
 16                 Task.Run(() => 
 17                      Producer(i)
 18                 );
 19                 // Task.Run(Producer3);
 20                 // Task.Run(ProducerQueue);
 21                 Thread.Sleep(300);
 22             }
 23         }
 24         /// <summary>
 25         /// 如果處理程序耗時>請求耗時,也就是說引起並發,就會導致死鎖
 26         /// </summary>
 27         static void Producer(int i)
 28         {
 29             var result = Process(i).Result;
 30             //或者
 31             //Process().Wait();
 32         }
 33         /// <summary>
 34         /// 正常
 35         /// </summary>
 36         static void Producer2(int i)
 37         {
 38             var result = Process(i).ConfigureAwait(false);
 39         }
 40         //cpu 內存均正常
 41         static async Task Producer3(int i)
 42         {
 43             await Process(i);
 44         }
 45 
 46         /// <summary>
 47         /// 
 48         /// </summary>
 49         static void ProducerQueue(int i)
 50         {
 51             ProcessQueue(i).Wait();
 52             //或者
 53             //Process().Wait();
 54         }
 55         /// <summary>
 56         /// 正常
 57         /// </summary>
 58         static void ProducerQueue2(int i)
 59         {
 60             var result = ProcessQueue(i).ConfigureAwait(false);
 61         }
 62         //cpu 內存均正常
 63         static async Task ProducerQueue3(int i)
 64         {
 65             await ProcessQueue(i);
 66         }
 67 
 68         static async Task<bool> Process(int i)
 69         {
 70             ConsoleWrite($"Start{i}");
 71             await Task.Run(() =>
 72             {
 73                 //模擬任務執行耗時
 74                 Thread.Sleep(2000);
 75             });
 76 
 77             ConsoleWrite($"End{i}");
 78             return true;
 79         }
 80 
 81 
 82 
 83         static async Task ProcessQueue(int i)
 84         {
 85             ConsoleWrite($"Start{i}");
 86             ThreadPool.QueueUserWorkItem(state =>
 87             {
 88                 ConsoleWrite("Hello" + (string)state);
 89             }, await GetName(i));
 90             ConsoleWrite($"End{i}");
 91         }
 92 
 93         private static async Task<string> GetName(int i)
 94         {
 95             Thread.Sleep(1000);
 96             Random r = new Random();
 97             return $"ZhiXin[{r.Next(100, 999)}]-[{i}]";
 98         }
 99         private static string GetCurrentThreadID()
100         {
101             return $" {DateTime.Now.ToLongTimeString()} --ThreadId[{Thread.CurrentThread.ManagedThreadId.ToString("0000")}]";
102         }
103         private static void ConsoleWrite(string type)
104         {
105             if (type.Contains("Start"))
106             {
107                 //Console.BackgroundColor = ConsoleColor.Blue; //設置背景色
108                 Console.ForegroundColor = ConsoleColor.Green; //設置前景色,即字體顏色
109             }
110             else if (type.Contains("End"))
111             {
112                 // Console.BackgroundColor = ConsoleColor.Red; //設置背景色
113                 Console.ForegroundColor = ConsoleColor.Red; //設置前景色,即字體顏色
114             }
115             Console.WriteLine($"{type} - " + GetCurrentThreadID());
116         }
117     }
118 }
使用.Result異步調用

結果如下:

測試代碼如下:

  1 using System;
  2 using System.Threading;
  3 using System.Threading.Tasks;
  4 
  5 namespace AsyncTest
  6 {
  7     class Program
  8     {
  9         static void Main(string[] args)
 10         {
 11             Console.ReadKey();
 12             //模擬並發
 13             for (int i = 0; i < 300; i++)
 14             {
 15                
 16                 Task.Run(() => 
 17                      Producer3(i)
 18                 );
 19                 // Task.Run(Producer3);
 20                 // Task.Run(ProducerQueue);
 21                 Thread.Sleep(300);
 22             }
 23         }
 24         /// <summary>
 25         /// 如果處理程序耗時>請求耗時,也就是說引起並發,就會導致死鎖
 26         /// </summary>
 27         static void Producer(int i)
 28         {
 29             var result = Process(i).Result;
 30             //或者
 31             //Process().Wait();
 32         }
 33         /// <summary>
 34         /// 正常
 35         /// </summary>
 36         static void Producer2(int i)
 37         {
 38             var result = Process(i).ConfigureAwait(false);
 39         }
 40         //cpu 內存均正常
 41         static async Task Producer3(int i)
 42         {
 43             await Process(i);
 44         }
 45 
 46         /// <summary>
 47         /// 
 48         /// </summary>
 49         static void ProducerQueue(int i)
 50         {
 51             ProcessQueue(i).Wait();
 52             //或者
 53             //Process().Wait();
 54         }
 55         /// <summary>
 56         /// 正常
 57         /// </summary>
 58         static void ProducerQueue2(int i)
 59         {
 60             var result = ProcessQueue(i).ConfigureAwait(false);
 61         }
 62         //cpu 內存均正常
 63         static async Task ProducerQueue3(int i)
 64         {
 65             await ProcessQueue(i);
 66         }
 67 
 68         static async Task<bool> Process(int i)
 69         {
 70             ConsoleWrite($"Start{i}");
 71             await Task.Run(() =>
 72             {
 73                 //模擬任務執行耗時
 74                 Thread.Sleep(2000);
 75             });
 76 
 77             ConsoleWrite($"End{i}");
 78             return true;
 79         }
 80 
 81 
 82 
 83         static async Task ProcessQueue(int i)
 84         {
 85             ConsoleWrite($"Start{i}");
 86             ThreadPool.QueueUserWorkItem(state =>
 87             {
 88                 ConsoleWrite("Hello" + (string)state);
 89             }, await GetName(i));
 90             ConsoleWrite($"End{i}");
 91         }
 92 
 93         private static async Task<string> GetName(int i)
 94         {
 95             Thread.Sleep(1000);
 96             Random r = new Random();
 97             return $"ZhiXin[{r.Next(100, 999)}]-[{i}]";
 98         }
 99         private static string GetCurrentThreadID()
100         {
101             return $" {DateTime.Now.ToLongTimeString()} --ThreadId[{Thread.CurrentThread.ManagedThreadId.ToString("0000")}]";
102         }
103         private static void ConsoleWrite(string type)
104         {
105             if (type.Contains("Start"))
106             {
107                 //Console.BackgroundColor = ConsoleColor.Blue; //設置背景色
108                 Console.ForegroundColor = ConsoleColor.Green; //設置前景色,即字體顏色
109             }
110             else if (type.Contains("End"))
111             {
112                 // Console.BackgroundColor = ConsoleColor.Red; //設置背景色
113                 Console.ForegroundColor = ConsoleColor.Red; //設置前景色,即字體顏色
114             }
115             Console.WriteLine($"{type} - " + GetCurrentThreadID());
116         }
117     }
118 }
使用await關鍵字異步調用

 

結果如下:

 

 

 

 ps:截屏工具 ScreenToGif

參考:

又踩.NET Core的坑:在同步方法中調用異步方法Wait時發生死鎖(deadlock)

一碼阻塞,萬碼等待:ASP.NET Core 同步方法調用異步方法“死鎖”的真相

.NET Core中遇到奇怪的線程死鎖問題:內存與線程數不停地增長

 C#同步方法中如何調用異步方法?值得一看

 理解C#中的ConfigureAwait

 bindot:https://www.cnblogs.com/bindot/p/cpu100.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM