CPU 100% 問(wèn)題分析,我們把博客園踩過(guò)的坑又踩了一遍《二》(補(bǔ)充)
問(wèn)題如下:
針對(duì).net core 異常奇怪問(wèn)題分析
- cpu 和內(nèi)存不高,但是線上系統(tǒng)運(yùn)行很卡
- cpu使用率瞬時(shí)升高,甚至突破100%(負(fù)載突然升高)
- 其它服務(wù)(或者進(jìn)程外的資源)傳入負(fù)載能力超出(或提示連接超時(shí)),比如提示(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))
- 也可能是一次顯示為"較長(zhǎng)"的數(shù)據(jù)庫(kù)查詢
- 或者任何非cpu活動(dòng)(如任何I/O或延遲),因此似乎非常I/O 操作隨機(jī)需要的時(shí)間比它應(yīng)該需要的時(shí)間長(zhǎng)
- 線程數(shù)莫名奇妙的不斷升高
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
static void Main(string[] args) { //按鍵后開始執(zhí)行 Console.ReadKey(); //模擬并發(fā) while (true) { Task.Run(Producer); Thread.Sleep(200); } } /// <summary> /// 如果處理程序耗時(shí)>請(qǐng)求耗時(shí),也就是說(shuō)引起并發(fā),就會(huì)導(dǎo)致死鎖 /// </summary> static void Producer() { var result = Process().Result; //或者 //Process().Wait(); } static async Task<bool> Process() { Console.WriteLine("Start - " + DateTime.Now.ToLongTimeString()); await Task.Run(() => { //模擬任務(wù)執(zhí)行耗時(shí) Thread.Sleep(1000); }); Console.WriteLine("Ended - " + DateTime.Now.ToLongTimeString()); return true; }
執(zhí)行效果:

以上可看出:
1、控制臺(tái)執(zhí)行5-10個(gè)任務(wù)后,不再執(zhí)行Ended 語(yǔ)句的任何內(nèi)容(Ended語(yǔ)句全部被阻塞)
2、內(nèi)存占用穩(wěn)步上升
3、AsyncTest.exe 線程每秒增加一個(gè)
解決方案:
var result = Process().ConfigureAwait(false);
或修改為異步方法(強(qiáng)烈推薦)
static async Task Producer() { await Process(); }
---補(bǔ)充 2021.2.26-------------------
優(yōu)化代碼后進(jìn)一步測(cè)試
測(cè)試代碼如下:
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 //模擬并發(fā) 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 /// 如果處理程序耗時(shí)>請(qǐng)求耗時(shí),也就是說(shuō)引起并發(fā),就會(huì)導(dǎo)致死鎖 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 內(nèi)存均正常 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 內(nèi)存均正常 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 //模擬任務(wù)執(zhí)行耗時(shí) 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; //設(shè)置背景色 108 Console.ForegroundColor = ConsoleColor.Green; //設(shè)置前景色,即字體顏色 109 } 110 else if (type.Contains("End")) 111 { 112 // Console.BackgroundColor = ConsoleColor.Red; //設(shè)置背景色 113 Console.ForegroundColor = ConsoleColor.Red; //設(shè)置前景色,即字體顏色 114 } 115 Console.WriteLine($"{type} - " + GetCurrentThreadID()); 116 } 117 } 118 }
結(jié)果如下:

測(cè)試代碼如下:
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 //模擬并發(fā) 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 /// 如果處理程序耗時(shí)>請(qǐng)求耗時(shí),也就是說(shuō)引起并發(fā),就會(huì)導(dǎo)致死鎖 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 內(nèi)存均正常 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 內(nèi)存均正常 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 //模擬任務(wù)執(zhí)行耗時(shí) 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; //設(shè)置背景色 108 Console.ForegroundColor = ConsoleColor.Green; //設(shè)置前景色,即字體顏色 109 } 110 else if (type.Contains("End")) 111 { 112 // Console.BackgroundColor = ConsoleColor.Red; //設(shè)置背景色 113 Console.ForegroundColor = ConsoleColor.Red; //設(shè)置前景色,即字體顏色 114 } 115 Console.WriteLine($"{type} - " + GetCurrentThreadID()); 116 } 117 } 118 }
結(jié)果如下:

ps:截屏工具 ScreenToGif
參考:
又踩.NET Core的坑:在同步方法中調(diào)用異步方法Wait時(shí)發(fā)生死鎖(deadlock)
一碼阻塞,萬(wàn)碼等待:ASP.NET Core 同步方法調(diào)用異步方法“死鎖”的真相

浙公網(wǎng)安備 33010602011771號(hào)