Advanced .Net Debugging 5:基本調試任務(線程的操作、代碼審查、CLR內部的命令、診斷命令和崩潰轉儲文件)

来源:https://www.cnblogs.com/PatrickLiu/p/18060906
-Advertisement-
Play Games

在.NET中Newtonsoft.Json(Json.NET)是我們常用來進行Json序列化與反序列化的庫。 而在使用中常會遇到反序列化Json時,遇到不規則的Json數據解構而拋出異常。 Newtonsoft.Json 支持序列化和反序列化過程中的錯誤處理。 允許您捕獲錯誤並選擇是處理它並繼續序列 ...


一、介紹
    
這是我的《Advanced .Net Debugging》這個系列的第五篇文章。今天這篇文章的標題雖然叫做“基本調試任務”,但是這章的內容還是挺多的。上一篇我們瞭解了一些調.NET 框架中必要的概念,比如:記憶體轉儲、值類型轉儲、引用類型轉儲、數組轉儲和異常轉儲等,我們既能做到知其然,又能做到眼見為實,知其所以然,對我們分析.NET 程式有很大的幫助。今天這篇文章主要涉及的內容是線程的操作、代碼的審查和診斷命令等。SOSEX擴展的內容我就省略了,因為我這個系列的是基於 .NET 8 版本來寫的,SOSEX是基於 .NET Framework 版本的,如果大家想瞭解其內容,可以查看我的【高級調試】系列(我當前寫的是《Advanced .Net Debugging》系列,是不一樣的),當然,也可以看原書。【高級調試】系列主要是集中在 .NET Framework 版本的。如果我們想成為一名合格程式員,這些調試技巧都是必須要掌握的。
    如果在沒有說明的情況下,所有代碼的測試環境都是 Net 8.0,如果有變動,我會在項目章節里進行說明。好了,廢話不多說,開始我們今天的調試工作。

     調試環境我需要進行說明,以防大家不清楚,具體情況我已經羅列出來。
          操作系統:Windows Professional 10
          調試工具:Windbg Preview(Debugger Client:1.2306.1401.0,Debugger engine:10.0.25877.1004)和 NTSD(10.0.22621.2428 AMD64)
          下載地址:可以去Microsoft Store 去下載
          開發工具:Microsoft Visual Studio Community 2022 (64 位) - Current版本 17.8.3

          Net 版本:.Net 8.0
          CoreCLR源碼:源碼下載
二、調試源碼
    廢話不多說,本節是調試的源碼部分,沒有代碼,當然就談不上測試了,調試必須有載體。

    2.1、ExampleCore_3_1_9
 1 namespace ExampleCore_3_1_9
 2 {
 3     internal class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             int a = 10;
 8             int b = 11;
 9             Console.WriteLine("X={0},Y={1}", a, b);
10             Test(12);
11             Console.ReadKey();
12         }
13 
14         private static void Test(int c)
15         {
16             Task.Run(Run1);
17             Task.Run(Run2);
18             Task.Run(Run3);
19         }
20 
21         private static void Run1()
22         {
23             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run1 正在運行");
24             Console.ReadLine();
25             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run1 結束運行");
26         }
27 
28         private static void Run2()
29         {
30             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run2 正在運行");
31             Console.ReadLine();
32             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run2 結束運行");
33         }
34 
35         private static void Run3()
36         {
37             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run3 正在運行");
38             Console.ReadLine();
39             Console.WriteLine($"tid={Environment.CurrentManagedThreadId},Run3 結束運行");
40         }
41     }
42 }
View Code
    2.2、ExampleCore_3_1_10
 1 namespace ExampleCore_3_1_10
 2 {
 3     internal class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             var sum = Sum(10, 11);
 8             Console.WriteLine($"sum={sum}");
 9             Console.ReadLine();
10         }
11 
12         private static int Sum(int a, int b)
13         {
14             int i = a;
15             int j = b;
16             var sum = i + j;
17             return sum;
18         }
19     }
20 }
View Code
    2.3、ExampleCore_3_1_11
 1 namespace ExampleCore_3_1_11
 2 {
 3     internal class Program
 4     {
 5         private static List<byte[]> list = new List<byte[]>();
 6 
 7         static void Main(string[] args)
 8         {
 9             for (int i = 0; i < 100; i++)
10             {
11                 list.Add(new byte[100000]);
12             }
13             Console.WriteLine("數據添加完畢!");
14             Console.ReadLine();
15         }
16     }
17 }
View Code
    2.4、ExampleCore_3_1_12
 1 namespace ExampleCore_3_1_12
 2 {
 3     internal class Program
 4     {
 5         static void Main(string[] args)
 6         {
 7             Console.WriteLine("請輸入一個除數:");
 8             var num = Console.ReadLine();
 9             var result = 10 / Convert.ToInt32(num);
10 
11             Console.ReadLine();
12         }
13     }
14 }
View Code
三、基礎知識

    3.1、線程的操作

        在非托管代碼調試中,所有與線程相關的調試器命令都是以非托管 Windows 線程為基礎的,換個說法就是,用於調試非托管代碼的調試器命令使用的就是非托管 Windows 線程,調試器命令知道如何轉儲我們要轉儲的對象。但是,托管代碼就不一樣了,它的線程有自己的結構,調試器本身是無法對調用棧進行遍歷的。
        我們知道,CLR 能對托管代碼進行動態轉換,並且 JIT 編譯器可以將生成的機器代碼放在它認為合適的地方。非托管調試器是不知道 JIT 編譯器的任何知識,它也不知道生成的代碼放在何處,因此就不能正確的顯示棧回溯。

        3.1.1、ClrStack
            A、基礎知識
                SOS 調試器擴展提供了一個專門查看托管函數調用棧的命令,畢竟只有 JIT 編譯器更熟悉托管函數,也知道編譯後的機器碼放在什麼位置。
                這個命令就是【!clrstack】。
                !clrstack -a(all):這個命令表示將線程棧中的所有局部變數和參數全部輸出。
                !clrstack -p(parameter):這個命令表示將線程棧中的參數全部輸出。
                !clrstack -l(locals):這個命令表示將線程棧中的所有局部變數全部輸出。

                我們還可以查看所有托管線程棧,可以使用【~*e】命令。
                請註意:如果 ClrStack 命令在非托管線程的上下文中運行,將會顯示一個錯誤:
1 0:006> !clrstack
2 OS Thread Id: 0x335c (6)
3 Unable to walk the managed stack. The current thread is likely not a 
4 managed thread. You can run !clrthreads to get a list of managed threads in
5 the process
6 Failed to start stack walk: 80070057

            B、眼見為實
                調試源碼:ExampleCore_3_1_9
                調試任務:ClrStack 命令使用
                1)、NTSD 調試
                    編譯項目,打開【Visual Studio 2022 Developer Command Prompt v17.9.2】命令行工具,輸入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_9\bin\Debug\net8.0\ExampleCore_3_1_9.exe】。
                    

                    打開【NTSD】調試器視窗。
                    

                    使用【g】命令運行調試器,知道調試器有如圖輸出,調試器會卡住暫停。
                    

                    按組合鍵【ctrl+c】進入中斷模式,在所有操作之前,我們先切換到托管線程,執行命令【~0s】。

1 0:003> ~0s
2 coreclr!CorSigUncompressElementType_EndPtr+0x18 [inlined in coreclr!MetaSig::CompareElementType+0x1d0]:
3 00007ffb`98b68e40 48ffc0          inc     rax

                    我們先使用【!clrstack】命令,後面不跟任何命令開關。

 1 0:000> !clrstack
 2 OS Thread Id: 0x3de4 (0)
 3         Child SP               IP Call Site
 4 000000F08ABCDFF8 00007ffb98b68e40 [ExternalMethodFrame: 000000f08abcdff8]
 5 000000F08ABCE5D0 00007FFC5382F269 System.Text.DecoderDBCS.GetChars(Byte[], Int32, Int32, Char[], Int32, Boolean)
 6 000000F08ABCE660 00007FFB92A28A51 System.IO.StreamReader.ReadBuffer()
 7 000000F08ABCE6B0 00007FFB92A290A4 System.IO.StreamReader.ReadLine()
 8 000000F08ABCE760 00007FFC5383005D System.IO.SyncTextReader.ReadLine()
 9 000000F08ABCE7B0 00007FFC53829319 System.Console.ReadLine()
10 000000F08ABCE7E0 00007FFB391219CF ExampleCore_3_1_9.Program.Main(System.String[])

                    它羅列出了調用棧。如果想查看每個棧幀的參數,我們可以使用【!clrstack -p】命令,很簡單,就不多說了。

1 0:000> !clrstack -p
2 OS Thread Id: 0x3de4 (0)
3         Child SP               IP Call Site
4 000000F08ABCDFF8 00007ffb98b68e40 [ExternalMethodFrame: 000000f08abcdff8]
5 。。。。。。(省略了)
6 000000F08ABCE7E0 00007FFB391219CF ExampleCore_3_1_9.Program.Main(System.String[])
7     PARAMETERS:(這裡就是參數所在地)
8         args (0x000000F08ABCE830) = 0x000002664e008ea0

                    如果想查看每個棧幀的局部變數,可以使用【!clrstack -l】命令。

1 0:000> !clrstack -l
2 OS Thread Id: 0x3de4 (0)
3         Child SP               IP Call Site
4 000000F08ABCDFF8 00007ffb98b68e40 [ExternalMethodFrame: 000000f08abcdff8]
5 。。。。。。(省略了)
6 000000F08ABCE7E0 00007FFB391219CF ExampleCore_3_1_9.Program.Main(System.String[])
7     LOCALS:(以下就是局部變數)
8         0x000000F08ABCE81C = 0x000000000000000a
9         0x000000F08ABCE818 = 0x000000000000000b

                    如果想查看每一棧幀的局部變數和參數,可以使用【!clrstack -a】命令。

 1 0:000> !clrstack -a
 2 OS Thread Id: 0x3de4 (0)
 3         Child SP               IP Call Site
 4 000000F08ABCDFF8 00007ffb98b68e40 [ExternalMethodFrame: 000000f08abcdff8]
 5 。。。。。。(省略了)
 6 000000F08ABCE7E0 00007FFB391219CF ExampleCore_3_1_9.Program.Main(System.String[])
 7     PARAMETERS:(這裡是參數區域)
 8         args (0x000000F08ABCE830) = 0x000002664e008ea0
 9     LOCALS:(這裡是局部變數區域)
10         0x000000F08ABCE81C = 0x000000000000000a
11         0x000000F08ABCE818 = 0x000000000000000b

                    很簡單,就不多數了。
                    還有一個命令,我們要熟悉一下,那就是~*e 命令。
                    ~ 命令輸出所有線程列表。

 1 0:000> ~
 2 .  0  Id: 3f64.3de4 Suspend: 1 Teb: 000000f0`8acb8000 Unfrozen
 3    1  Id: 3f64.ab4 Suspend: 1 Teb: 000000f0`8acd6000 Unfrozen ".NET Tiered Compilation Worker"
 4    2  Id: 3f64.b08 Suspend: 1 Teb: 000000f0`8acd8000 Unfrozen
 5 #  3  Id: 3f64.6d0 Suspend: 1 Teb: 000000f0`8acda000 Unfrozen
 6    4  Id: 3f64.220c Suspend: 1 Teb: 000000f0`8acc0000 Unfrozen ".NET EventPipe"
 7    5  Id: 3f64.1830 Suspend: 1 Teb: 000000f0`8acc2000 Unfrozen ".NET Debugger"
 8    6  Id: 3f64.3c34 Suspend: 1 Teb: 000000f0`8acc4000 Unfrozen ".NET Finalizer"
 9    8  Id: 3f64.10d0 Suspend: 1 Teb: 000000f0`8acca000 Unfrozen ".NET TP Worker"
10    9  Id: 3f64.3e9c Suspend: 1 Teb: 000000f0`8accc000 Unfrozen ".NET TP Gate"
11   10  Id: 3f64.3d90 Suspend: 1 Teb: 000000f0`8acce000 Unfrozen ".NET TP Worker"
12   11  Id: 3f64.1e48 Suspend: 1 Teb: 000000f0`8acd0000 Unfrozen ".NET TP Worker"

                    ~* 命令,顯示所有線程列表和入口函數。

 1 0:000> ~*
 2 .  0  Id: 3f64.3de4 Suspend: 1 Teb: 000000f0`8acb8000 Unfrozen
 3       Start: apphost!wmainCRTStartup (00007ff7`8a2b1360)
 4       Priority: 0  Priority class: 32  Affinity: f
 5    1  Id: 3f64.ab4 Suspend: 1 Teb: 000000f0`8acd6000 Unfrozen ".NET Tiered Compilation Worker"
 6       Start: coreclr!TieredCompilationManager::BackgroundWorkerBootstrapper0 (00007ffb`98c833f0)
 7       Priority: 0  Priority class: 32  Affinity: f
 8    2  Id: 3f64.b08 Suspend: 1 Teb: 000000f0`8acd8000 Unfrozen
 9       Start: KERNELBASE!CtrlRoutine (00007ffc`651d9c80)
10       Priority: 2  Priority class: 32  Affinity: f
11 #  3  Id: 3f64.6d0 Suspend: 1 Teb: 000000f0`8acda000 Unfrozen
12       Start: ntdll!DbgUiRemoteBreakin (00007ffc`6791ba10)
13       Priority: 0  Priority class: 32  Affinity: f
14    4  Id: 3f64.220c Suspend: 1 Teb: 000000f0`8acc0000 Unfrozen ".NET EventPipe"
15       Start: coreclr!server_thread (00007ffb`98c6b530)
16       Priority: 0  Priority class: 32  Affinity: f
17    5  Id: 3f64.1830 Suspend: 1 Teb: 000000f0`8acc2000 Unfrozen ".NET Debugger"
18       Start: coreclr!DebuggerRCThread::ThreadProcStatic (00007ffb`98c667f0)
19       Priority: 0  Priority class: 32  Affinity: f
20    6  Id: 3f64.3c34 Suspend: 1 Teb: 000000f0`8acc4000 Unfrozen ".NET Finalizer"
21       Start: coreclr!FinalizerThread::FinalizerThreadStart (00007ffb`98c4e370)
22       Priority: 2  Priority class: 32  Affinity: f
23    8  Id: 3f64.10d0 Suspend: 1 Teb: 000000f0`8acca000 Unfrozen ".NET TP Worker"
24       Start: coreclr!ThreadNative::KickOffThread (00007ffb`98c07340)
25       Priority: 0  Priority class: 32  Affinity: f
26    9  Id: 3f64.3e9c Suspend: 1 Teb: 000000f0`8accc000 Unfrozen ".NET TP Gate"
27       Start: coreclr!ThreadNative::KickOffThread (00007ffb`98c07340)
28       Priority: 0  Priority class: 32  Affinity: f
29   10  Id: 3f64.3d90 Suspend: 1 Teb: 000000f0`8acce000 Unfrozen ".NET TP Worker"
30       Start: coreclr!ThreadNative::KickOffThread (00007ffb`98c07340)
31       Priority: 0  Priority class: 32  Affinity: f
32   11  Id: 3f64.1e48 Suspend: 1 Teb: 000000f0`8acd0000 Unfrozen ".NET TP Worker"
33       Start: coreclr!ThreadNative::KickOffThread (00007ffb`98c07340)
34       Priority: 0  Priority class: 32  Affinity: f

                2)、Windbg Preview 調試
                    編譯項目,打開【Windbg Preview】,依次點擊【文件】--->【Launch executable】,載入我們的項目文件:ExampleCore_3_1_9.exe,進入調試器。繼續使用【g】命令,運行調試器。我們的控制台程式輸出如下內容,如圖:
                    

                    點擊【break】按鈕,中斷調試器的執行,由於,我們手動中斷程式執行,需要將線程切換到托管線程上,執行命令【~0s】。

1 0:001> ~0s
2 ntdll!NtReadFile+0x14:
3 00007ffc`678eae54 c3              ret

                    我們繼續使用【!clrstack】命令,輸出托管線程的調用棧。

 1 0:000> !clrstack
 2 OS Thread Id: 0x3b40 (0)【底層操作系統的ID】
 3         Child SP               IP Call Site
 4 000000D3A5F7E560 00007ffc678eae54 [InlinedCallFrame: 000000d3a5f7e560] 
 5 000000D3A5F7E560 00007ffc0bf676eb [InlinedCallFrame: 000000d3a5f7e560] 
 6 000000D3A5F7E530 00007ffc0bf676eb Interop+Kernel32.ReadFile(IntPtr, Byte*, Int32, Int32 ByRef, IntPtr) [/_/.../LibraryImports.g.cs @ 412]
 7 000000D3A5F7E620 00007ffc0bf6c9c0 System.ConsolePal+WindowsConsoleStream..../System/ConsolePal.Windows.cs @ 1150]
 8 000000D3A5F7E680 00007ffc0bf6c8bb System.ConsolePal+WindowsConsoleStream.Read(System.Span`1) [/_/src/libraries/....Windows.cs @ 1108]
 9 000000D3A5F7E6C0 00007ffc0bf6fb84 System.IO.ConsoleStream.Read(Byte[], Int32, Int32) [/_/src/libraries/.../ConsoleStream.cs @ 34]
10 000000D3A5F7E730 00007ffb8d1589c1 System.IO.StreamReader.ReadBuffer() [/_/src/libraries/System.Private.CoreLib/.../IO/StreamReader.cs @ 613]
11 000000D3A5F7E780 00007ffb8d1590a4 System.IO.StreamReader.ReadLine() [/_/src/libraries/System.Private.CoreLib/.../StreamReader.cs @ 802]
12 000000D3A5F7E830 00007ffc0bf7005d System.IO.SyncTextReader.ReadLine() [/_/src/libraries/System.Console/src/System/IO/SyncTextReader.cs @ 77]
13 000000D3A5F7E880 00007ffc0bf69319 System.Console.ReadLine() [/_/src/libraries/System.Console/src/System/Console.cs @ 752]
14 000000D3A5F7E8B0 00007ffb2e3419cf ExampleCore_3_1_9.Program.Main(System.String[]) [E:\Visual Studio\...\ExampleCore_3_1_9\Program.cs @ 11]

                    我們可以使用【!clrstack -l】,查看托管線程調用棧,並顯示每個棧幀的局部變數。

 1 0:000> !clrstack -l
 2 OS Thread Id: 0x3b40 (0)
 3         Child SP               IP Call Site
 4 000000D3A5F7E560 00007ffc678eae54 [InlinedCallFrame: 000000d3a5f7e560] 
 5 000000D3A5F7E560 00007ffc0bf676eb [InlinedCallFrame: 000000d3a5f7e560] 
 。。。。。。(省略了)49 
50 000000D3A5F7E8B0 00007ffb2e3419cf ExampleCore_3_1_9.Program.Main(System.String[]) [E:\Visual Studio\...\ExampleCore_3_1_9\Program.cs @ 11]
51     LOCALS:
52         0x000000D3A5F7E8EC = 0x000000000000000a
53         0x000000D3A5F7E8E8 = 0x000000000000000b 這就是我們的局部變數

                    如果我們想查看托管調用棧的參數,可以使用【!clrstack -p】命令,p(parameter)參數。

 1 0:000> !clrstack -p
 2 OS Thread Id: 0x3b40 (0)
 3         Child SP               IP Call Site
 4 000000D3A5F7E560 00007ffc678eae54 [InlinedCallFrame: 000000d3a5f7e560] 
 5 000000D3A5F7E560 00007ffc0bf676eb [InlinedCallFrame: 000000d3a5f7e560] 
 。。。。。。(省略了)47 
48 000000D3A5F7E8B0 00007ffb2e3419cf ExampleCore_3_1_9.Program.Main(System.String[]) [E:\Visual Studio\...\ExampleCore_3_1_9\Program.cs @ 11]
49     PARAMETERS:
50         args (0x000000D3A5F7E900) = 0x000001efb4408ea0(這個就是 Main 方法的 args 參數)

                    0x000001efb4408ea0 這個地址就是 Program.Main 方法的 args 參數,args 是字元串數組,是引用類型,我們可以直接使用【!dumpobj】來確認。

1 0:000> !dumpobj 0x000001efb4408ea0
2 Name:        System.String[]
3 MethodTable: 00007ffb2e3cfab0
4 EEClass:     00007ffb2e27c440
5 Tracked Type: false
6 Size:        24(0x18) bytes
7 Array:       Rank 1, Number of elements 0, Type CLASS (Print Array)
8 Fields:
9 None

                    如果想同時查看局部變數和參數,可以使用【!clrstack -a】命令。

 1 0:000> !clrstack -a
 2 OS Thread Id: 0x3b40 (0)
 3         Child SP               IP Call Site
 4 000000D3A5F7E560 00007ffc678eae54 [InlinedCallFrame: 000000d3a5f7e560] 
 5 000000D3A5F7E560 00007ffc0bf676eb [InlinedCallFrame: 000000d3a5f7e560] 
 6 。。。。。。(省略了)
 7 
 8 000000D3A5F7E8B0 00007ffb2e3419cf ExampleCore_3_1_9.Program.Main(System.String[]) [E:\Visual Studio\...\ExampleCore_3_1_9\Program.cs @ 11]
 9     PARAMETERS:
10         args (0x000000D3A5F7E900) = 0x000001efb4408ea0 (這是參數)
11     LOCALS:
12         0x000000D3A5F7E8EC = 0x000000000000000a (這是局部變數)
13         0x000000D3A5F7E8E8 = 0x000000000000000b (這是局部變數)

        3.1.2、Threads
            A、基礎知識
                如何你想枚舉出進程中所有的托管代碼線程,可以使用【!threads】命令,或者簡寫形式【!t】。當然,這個命令也有一些開關設置,-live 只羅列出那些處於活躍狀態的線程的信息,-special 只輸出進程中所有“特殊的”線程,比如:垃圾收集線程、調試器線程、線程池定時器線程等。
            B、眼見為實
                調試源碼:ExampleCore_3_1_9
                調試任務:Threads 命令的使用
                1)、NTSD 調試
                    編譯項目,打開【Visual Studio 2022 Developer Command Prompt v17.9.2】命令行工具,輸入命令【NTSD E:\Visual Studio 2022\Source\Projects\AdvancedDebug.NetFramework.Test\ExampleCore_3_1_9\bin\Debug\net8.0\ExampleCore_3_1_9.exe】,打開調試器視窗。
                    

                    

                    使用【g】命令,繼續運行調試器,等到調試器輸出以下內容:
                    

                    按【ctrl+c】組合鍵進入調試模式。

 1 0:013> !threads
 2 ThreadCount:      8
 3 UnstartedThread:  1
 4 BackgroundThread: 5
 5 PendingThread:    1
 6 DeadThread:       1
 7 Hosted Runtime:   no

              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在當今數字化時代,構建高效、可靠的分散式系統是許多企業和開發團隊面臨的挑戰。微軟的 Orleans 框架為解決這些挑戰提供了一個強大而簡單的解決方案。本文將介紹 Orleans 的核心概念,並通過一個簡單的示例代碼來演示其用法。 什麼是 Orleans? Orleans 是由微軟開發的一個開源分散式 ...
  • 嗯,構建模塊,一行代碼的事情,愣是讓我寫成了一篇教程,太難了。在這個入門教程的第三部分中,我們學習瞭如何使用.NET Emit 構建模塊(Module)。通過創建和定義模塊,我們可以更好地組織和管理我們的代碼。在這個過程中,我們瞭解瞭如何使用 AssemblyBuilder 和 ModuleBuil... ...
  • 在 PostgreSQL 中,bytea_output 參數控制在查詢結果中 bytea 類型的顯示格式。預設情況下,bytea_output 的值為 hex,這意味著在查詢結果中,bytea 類型的數據以十六進位格式顯示。但是,如果你的應用程式期望以二進位格式獲取圖像數據,則將 bytea_out... ...
  • 為了優化我們公司網站的性能,我最近引入了瀏覽器預載入技術(Preload)。 這項技術可以顯著減少級聯情況,提高資源載入的並行度,從而加速網站的載入速度。 Preload的原理 Preload的原理是在瀏覽器解析HTML文檔時,提前載入頁面所需的關鍵資源,如樣式表、腳本文件和字體等。 通過預載入這些 ...
  • 前言 文本主要講 MinimalApis 中的使用自定義IResultModel和系統自帶IResult做響應返回值。 MinimalApis支持以下類型的返回值: string - 這包括 Task<string> 和 ValueTask<string> T(任何其他類型)- 這包括 Task<T ...
  • 一:背景 1. 講故事 前幾天有位朋友找到我,說他們的API服務程式跑著跑著CPU滿了降不下去,讓我幫忙看下怎麼回事,現在貌似民間只有我一個人專註dump分析,還是申明一下我dump分析是免費的,如果想學習.NET高級調試的分析技術,可以來我的訓練營看看,話不多說,dump分析走起! 二:WinDb ...
  • 前言 好久不用Arcgis,突然發現想用時,有點不會安裝了,所以這裡記錄一下安裝過程。 下載Arcgis 首先,下載一個arcgis版本,我這裡下的是10.1。 推薦【 gis思維(公眾號)】,【麻辣GIS(網站)】。 當然了,這都是很舊很舊的版本了,基本上沒有三維功能。 一定要下載帶註冊機的。 a ...
  • 在本章節中,我們討論瞭如何使用 C# Emit 來構建動態程式集,以獲得 AssemblyBuilder 這個程式集構建器,開啟構建程式集的第一步。同時我們也討論瞭如何使用 C# Emit 來構建動態程式集以及程式集的持久化。同時還分享了自己的乾貨,如何使用 CodeDom 和 Roslyn 來構建... ...
一周排行
    -Advertisement-
    Play Games
  • 基於.NET Framework 4.8 開發的深度學習模型部署測試平臺,提供了YOLO框架的主流系列模型,包括YOLOv8~v9,以及其系列下的Det、Seg、Pose、Obb、Cls等應用場景,同時支持圖像與視頻檢測。模型部署引擎使用的是OpenVINO™、TensorRT、ONNX runti... ...
  • 十年沉澱,重啟開發之路 十年前,我沉浸在開發的海洋中,每日與代碼為伍,與演算法共舞。那時的我,滿懷激情,對技術的追求近乎狂熱。然而,隨著歲月的流逝,生活的忙碌逐漸占據了我的大部分時間,讓我無暇顧及技術的沉澱與積累。 十年間,我經歷了職業生涯的起伏和變遷。從初出茅廬的菜鳥到逐漸嶄露頭角的開發者,我見證了 ...
  • C# 是一種簡單、現代、面向對象和類型安全的編程語言。.NET 是由 Microsoft 創建的開發平臺,平臺包含了語言規範、工具、運行,支持開發各種應用,如Web、移動、桌面等。.NET框架有多個實現,如.NET Framework、.NET Core(及後續的.NET 5+版本),以及社區版本M... ...
  • 前言 本文介紹瞭如何使用三菱提供的MX Component插件實現對三菱PLC軟元件數據的讀寫,記錄了使用電腦模擬,模擬PLC,直至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1. PLC開發編程環境GX Works2,GX Works2下載鏈接 https:// ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • 1、jQuery介紹 jQuery是什麼 jQuery是一個快速、簡潔的JavaScript框架,是繼Prototype之後又一個優秀的JavaScript代碼庫(或JavaScript框架)。jQuery設計的宗旨是“write Less,Do More”,即倡導寫更少的代碼,做更多的事情。它封裝 ...
  • 前言 之前的文章把js引擎(aardio封裝庫) 微軟開源的js引擎(ChakraCore))寫好了,這篇文章整點js代碼來測一下bug。測試網站:https://fanyi.youdao.com/index.html#/ 逆向思路 逆向思路可以看有道翻譯js逆向(MD5加密,AES加密)附完整源碼 ...
  • 引言 現代的操作系統(Windows,Linux,Mac OS)等都可以同時打開多個軟體(任務),這些軟體在我們的感知上是同時運行的,例如我們可以一邊瀏覽網頁,一邊聽音樂。而CPU執行代碼同一時間只能執行一條,但即使我們的電腦是單核CPU也可以同時運行多個任務,如下圖所示,這是因為我們的 CPU 的 ...
  • 掌握使用Python進行文本英文統計的基本方法,並瞭解如何進一步優化和擴展這些方法,以應對更複雜的文本分析任務。 ...
  • 背景 Redis多數據源常見的場景: 分區數據處理:當數據量增長時,單個Redis實例可能無法處理所有的數據。通過使用多個Redis數據源,可以將數據分區存儲在不同的實例中,使得數據處理更加高效。 多租戶應用程式:對於多租戶應用程式,每個租戶可以擁有自己的Redis數據源,以確保數據隔離和安全性。 ...