成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

記一次 .NET 某電商醫藥網站 CPU 爆高分析

開發 后端
前些天有位朋友找到我,說他們的網站會有CPU瞬高的情況,在網上找相關資料最終找到我這邊,想讓我幫忙分析下咋回事?像這種CPU瞬高,比較好的方式就是用procdump自動化的抓取,萬不可手工去抓,接下來就上 windbg 分析吧。

一、背景

1. 講故事

準備明年把.NET高級調試的訓練營的課程進行重構,采用案例引導式,而CPU爆高類有不少是程序員在寫代碼的時候不注意時間復雜度,在數據量稍微大一點的情況直接幻化成了死循環,時間復雜度這東西是學校的數據結構課程,有心的朋友在寫多層循環的時候腦子里面一定要過一遍,今天就給大家帶一篇此類案例,也算是繼續豐富我的新課程體系。

前些天有位朋友找到我,說他們的網站會有CPU瞬高的情況,在網上找相關資料最終找到我這邊,想讓我幫忙分析下咋回事?像這種CPU瞬高,比較好的方式就是用procdump自動化的抓取,萬不可手工去抓,接下來就上 windbg 分析吧。

二、WinDbg分析

1. 為什么會CPU爆高

以終為始,先看看CPU是否真的高,可以用 !tp 和 !cpuid 命令觀察,這里稍微提一下,為什么要用 !cpuid 看看CPU的能力呢?這是因為我曾經分析過只有 2core 的CPU。尼瑪,只有2個core,還分析個毛線哈,干脆把機器關了,這樣CPU就不高了。。。自此以后我就留了一個心眼,輸出參考如下:

0:033> !tp
CPU utilization: 100%
Worker Thread: Total: 5 Running: 5 Idle: 0 MaxLimit: 32767 MinLimit: 4
Work Request in Queue: 11
    Unknown Function: 00007ffbfaa417d0  Context: 00000283733c3718
    Unknown Function: 00007ffbfaa417d0  Context: 0000027f26f50cb0
    Unknown Function: 00007ffbfaa417d0  Context: 0000028377199f58
    AsyncTimerCallbackCompletion TimerInfo@0000028371c46820
    AsyncTimerCallbackCompletion TimerInfo@0000028371d06800
    Unknown Function: 00007ffbfaa417d0  Context: 00000283756d3248
    Unknown Function: 00007ffbfaa417d0  Context: 0000027f26f63578
    Unknown Function: 00007ffbfaa417d0  Context: 00000283733d0160
    Unknown Function: 00007ffbfaa417d0  Context: 00000283756a72d8
    Unknown Function: 00007ffbfaa417d0  Context: 00000283771a6828
    Unknown Function: 00007ffbfaa417d0  Context: 000002837719d1f8
--------------------------------------
Number of Timers: 0
--------------------------------------
Completion Port Thread:Total: 3 Free: 2 MaxFree: 8 CurrentLimit: 2 MaxLimit: 1000 MinLimit: 4
0:033> !cpuid
CP  F/M/S  Manufacturer     MHz
 0  6,106,6  <unavailable>   2800
 1  6,106,6  <unavailable>   2800
 2  6,106,6  <unavailable>   2800
 3  6,106,6  <unavailable>   2800

從卦中可以看出當前線程池隊列稍有積壓,5個托管線程全部被打滿,并且當前機器是4個核,看樣子是有4個線程在滿負荷跑呀。。。

2. 線程都在干什么

為了追蹤線程都在干什么?使用 ~*e !clrstack 觀察各個線程的調用棧,結合程序的瞬高特性,捕獲了一個相對來說高度可疑的代碼,參考如下:

OS Thread Id: 0x2f00 (33)
        Child SP               IP Call Site
000000f2a42fd508 00007ffbfd72b0a7 System.String.Equals(System.String, System.String) [f:\dd\ndp\clr\src\BCL\system\string.cs @ 647]
000000f2a42fd510 00007ffba1715a0b xxx.StockAsyncDbTask+c__DisplayClass4_1.b__6(xxx.GoodsInfo)
000000f2a42fd540 00007ffba118c6ca System.Linq.Enumerable.FirstOrDefault[[System.__Canon, mscorlib]](System.Collections.Generic.IEnumerable`1<System.__Canon>, System.Func`2<System.__Canon,Boolean>)
000000f2a42fd5b0 00007ffba1716008 xxx.StockAsyncDbTask+c__DisplayClass4_0.b__2(xxx.GoodsInfo)
000000f2a42fd670 00007ffbfd720505 System.Collections.Generic.List`1[[System.__Canon, mscorlib]].ForEach(System.Action`1<System.__Canon>) [f:\dd\ndp\clr\src\BCL\system\collections\generic\list.cs @ 553]
000000f2a42fd6c0 00007ffba1349e7e xxx.SaveStockToDb()
000000f2a42fd760 00007ffba13487ed xxx.DoWork()
000000f2a42fd7b0 00007ffba1348631 xxx.QuartzScheduler.QuartzJob.Quartz.IJob.Execute(Quartz.IJobExecutionContext)
000000f2a42fd8b0 00007ffba0f8ca12 Quartz.Core.JobRunShell+d__9.MoveNext()
000000f2a42fdb80 00007ffba0f83150 System.Runtime.CompilerServices.AsyncTaskMethodBuilder.Start[[Quartz.Core.JobRunShell+d__9, Quartz]](d__9 ByRef) [f:\dd\ndp\clr\src\BCL\system\runtime\compilerservices\AsyncMethodBuilder.cs @ 322]
000000f2a42fdc30 00007ffba0f8309d Quartz.Core.JobRunShell.Run(System.Threading.CancellationToken)
000000f2a42fdd30 00007ffba0f829f4 Quartz.Core.QuartzSchedulerThread+c__DisplayClass28_0.b__0()
000000f2a42fdd60 00007ffbfd7abe4e System.Threading.Tasks.Task`1[[System.__Canon, mscorlib]].InnerInvoke() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Future.cs @ 680]
000000f2a42fddb0 00007ffbfd7aaf27 System.Threading.Tasks.Task.Execute() [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2498]
000000f2a42fddf0 00007ffbfd73df12 System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 980]
000000f2a42fdec0 00007ffbfd73dd95 System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\executioncontext.cs @ 928]
000000f2a42fdef0 00007ffbfd7ab1e1 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2827]
000000f2a42fdfa0 00007ffbfd7aa8c1 System.Threading.Tasks.Task.ExecuteEntry(Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\Tasks\Task.cs @ 2767]
000000f2a42fdfe0 00007ffbfd708e46 System.Threading.ThreadPoolWorkQueue.Dispatch() [f:\dd\ndp\clr\src\BCL\system\threading\threadpool.cs @ 820]

根據卦中的顯示找到了問題方法,為了保護客戶隱私,這里稍微會模糊一下,主要是看下復雜度的骨架結構。

圖片圖片

從卦象看里面至少包含了3層for循環,所以時間復雜度是 O(N3) 次方,學過數據結構和算法的朋友應該知道,這個復雜度不得了,要逆天了。

3. O(N3) 是禍根嗎?

要想知道 O(N3) 是不是禍根,得要看有沒有給它不停的施肥翻土,可以找找相關的集合,使用 !dso 命令觀察即可。

0:033> !dso
OS Thread Id: 0x2f00 (33)
RSP/REG          Object           Name
rbx              0000028227b4be70 xxx.GoodsInfo
000000F2A42FD520 0000028029c02038 System.Collections.Generic.List`1[[xxx.GoodsInfo, xxx.Model]]
...
000000F2A42FD708 0000027f277d3de8 System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[xxx_DataGrab, xxx.Data]]

0:033> !do 0000027f277d3de8
Name:        System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[xxx_DataGrab,xxx.Data]]
MethodTable: 00007ffba12b82f8
EEClass:     00007ffbfd345c10
Size:        80(0x50) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ffbfd1d8538  4001887        8       System.Int32[]  0 instance 0000027f27d51328 buckets
00007ffbfe422618  4001888       10 ...non, mscorlib]][]  0 instance 0000027f27d51350 entries
00007ffbfd1d85a0  4001889       38         System.Int32  1 instance                1 count
00007ffbfd1d85a0  400188a       3c         System.Int32  1 instance                1 version
00007ffbfd1d85a0  400188b       40         System.Int32  1 instance               -1 freeList
00007ffbfd1d85a0  400188c       44         System.Int32  1 instance                0 freeCount
00007ffbfd1c7790  400188d       18 ...Canon, mscorlib]]  0 instance 00000282274c1978 comparer
00007ffbfd1c57c0  400188e       20 ...Canon, mscorlib]]  0 instance 0000027f27cfc630 keys
00007ffbfd1eef60  400188f       28 ...Canon, mscorlib]]  0 instance 0000000000000000 values
00007ffbfd1d5dd8  4001890       30        System.Object  0 instance 0000000000000000 _syncRoot

0:033> !do 0000028029c02038
Name:        System.Collections.Generic.List`1[[xxx, xxx.Model]]
MethodTable: 00007ffba126e830
EEClass:     00007ffbfd362af8
Size:        40(0x28) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ffbfd1ee250  40018a0        8     System.__Canon[]  0 instance 00000283278195b0 _items
00007ffbfd1d85a0  40018a1       18         System.Int32  1 instance            21863 _size
00007ffbfd1d85a0  40018a2       1c         System.Int32  1 instance                0 _version
00007ffbfd1d5dd8  40018a3       10        System.Object  0 instance 0000000000000000 _syncRoot
00007ffbfd1ee250  40018a4        8     System.__Canon[]  0   static  <no information>

從卦中可以看到第一層的dictionary只有1條記錄,第二層的 List 有高達 2.1w 數據,第三層的 dbStocks 在線程棧沒有找到,我也懶得找到了,起碼發現了第二層的 list 確實比較大,加上數據的佐證,基本上就找到了問題所在,也滿足程序的瞬高的現象。

4. 解決方案

知道了復雜度高,優化的方向就是降低時間復雜度,將 O(N3) 降低到 O(N),方法就是在深層循環之前提前用 Dictionary 或者 HashSet 來預存數據,將后面的 for 循環變成字段的key查找,而key查找則是 O(1)。

為了讓大家有個宏觀概念,我讓 chatgpt 給我生成一個 O(N2) 到 O(N) 的例子,參考代碼如下:

public class GoodsInfo
{
    public int Spid { get; set; }
    // 其他屬性...
}
 
public class Stock
{
    public int Spid { get; set; }
    // 其他屬性...
}
 
public class Optimizer
{
    // 原始O(N^2)復雜度的查找方法
    public List<GoodsInfo> FindMatchingGoodsInfoO_N2(List<GoodsInfo> goodsInfos, List<Stock> stocks, int targetSpid)
    {
        List<GoodsInfo> result = new List<GoodsInfo>();
        foreach (var goodsInfo in goodsInfos)
        {
            foreach (var stock in stocks)
            {
                if (goodsInfo.Spid == stock.Spid && stock.Spid == targetSpid)
                {
                    result.Add(goodsInfo);
                }
            }
        }
        return result;
    }
 
    // 優化后的O(N)復雜度的查找方法
    public List<GoodsInfo> FindMatchingGoodsInfoO_N(List<GoodsInfo> goodsInfos, List<Stock> stocks, int targetSpid)
    {
        HashSet<int> stockSpids = new HashSet<int>(stocks.Select(s => s.Spid));
        List<GoodsInfo> result = new List<GoodsInfo>();
 
        foreach (var goodsInfo in goodsInfos)
        {
            if (stockSpids.Contains(goodsInfo.Spid) && goodsInfo.Spid == targetSpid)
            {
                result.Add(goodsInfo);
            }
        }
 
        return result;
    }
}

可以看到 chatgpt 很聰明,用 HashSet 來化煞。

三:總結

說實話像這種生產事故,我以前在公司的項目中也會偶發的遇到,都是趕時間,加班加點寫出來的代碼,只想把功能寫出來早點下班,復雜度高?后面再說吧。。。代碼寫的太好,容易被老板優化。

責任編輯:武曉燕 來源: 一線碼農聊技術
相關推薦

2021-10-27 07:30:32

.NETCPU論壇

2024-08-08 11:21:01

2022-10-24 07:48:37

.NETCPUGC

2021-05-17 07:43:06

Web站 CPU.NET

2023-05-12 17:42:22

CPUMES系統

2024-03-15 15:15:53

.NETCPU系統

2023-07-31 22:29:20

CPU.NETAPI

2021-04-21 07:38:41

CPU游戲站程序

2022-02-23 10:12:58

CPUWeb.NET

2023-11-01 10:46:12

.NET線程同步

2023-03-26 20:24:50

ERP網站系統

2021-02-25 10:00:19

企業安全互聯網云平臺安全

2021-10-09 10:24:08

NET爬蟲內存

2023-06-26 00:12:46

2024-12-27 13:31:18

.NETdump調試

2023-04-06 10:52:18

2024-03-28 12:56:36

2023-09-27 07:23:10

.NET監控軟件

2024-07-12 11:20:34

.NET崩潰視覺程序

2023-07-06 10:11:38

.NET模式dump
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久亚洲精品视频 | 国产yw851.c免费观看网站 | 久久性av| 日韩视频在线观看 | 一区亚洲 | 午夜影院 | 亚洲精品久久嫩草网站秘色 | 精品91av| 久久久久久国产 | 国产精品美女久久久久aⅴ国产馆 | 亚洲视频免费播放 | 久久99精品久久 | 免费一级黄色电影 | 丁香色婷婷 | 国产精品不卡视频 | 中文字幕日韩欧美一区二区三区 | 黄视频在线网站 | www.精品国产| 爱综合| 国产在线精品一区二区三区 | 91观看 | 天天天天操 | 日本三级日产三级国产三级 | 日日摸夜夜添夜夜添特色大片 | 国产色99 | 精品一区二区三区在线视频 | 2022精品国偷自产免费观看 | 国产精品国产三级国产aⅴ中文 | 亚洲九九色 | 亚洲欧美综合网 | 成人在线免费 | 日本一区不卡 | 国产精品视频www | 高清欧美性猛交 | 亚洲精品电影网在线观看 | 国产精品久久久久aaaa樱花 | 久久久成人动漫 | 国产视频一区二区在线观看 | 日韩www| 97久久精品午夜一区二区 | 99这里只有精品 |