CPU 100% 问题分析,我们把博客园踩过的坑又踩了一遍《二》(补充)
问题如下:
针对.net core 异常奇怪问题分析
- cpu 和内存不高,但是线上系统运行很卡
- cpu使用率瞬时升高,甚至突破100%(负载突然升高)
- 其它服务(或者进程外的资源)传入负载能力超出(或提示连接超时),比如提示(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))
- 也可能是一次显示为"较长"的数据库查询
- 或者任何非cpu活动(如任何I/O或延迟),因此似乎非常I/O 操作随机需要的时间比它应该需要的时间长
- 线程数莫名奇妙的不断升高
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) { //按键后开始执行 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 }
结果如下:
测试代码如下:
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 }
结果如下:
ps:截屏工具 ScreenToGif
参考:
又踩.NET Core的坑:在同步方法中调用异步方法Wait时发生死锁(deadlock)
一码阻塞,万码等待:ASP.NET Core 同步方法调用异步方法“死锁”的真相
原创不易,转载请声明 bindot
https://www.cnblogs.com/bindot/