主頁 > .NET開發 > 執行緒(一)——執行緒,執行緒池,Task概念+代碼實踐

執行緒(一)——執行緒,執行緒池,Task概念+代碼實踐

2020-12-15 06:07:46 .NET開發

執行緒(一)——執行緒,執行緒池,Task概念+代碼實踐

目錄
  • 執行緒(一)——執行緒,執行緒池,Task概念+代碼實踐
    • 摘要
    • 1 執行緒安全
      • 1.1 未出現執行緒搶占
      • 1.2 執行緒搶占
      • 1.3 避免執行緒搶占
    • 2 執行緒阻塞
    • 3 Thread.yield()和Thread.sleep(0)
    • 4 執行緒如何作業
    • 5 執行緒與行程
    • 6 執行緒的使用和濫用
    • 7 執行緒傳參
      • 7.1 lambda運算式傳參
      • 7.2 執行緒start方法傳參
      • 7.3 執行緒創建需要時間
    • 8 執行緒命名
    • 9 前臺執行緒與后臺執行緒
    • 10 執行緒優先級
    • 11 例外處理
    • 12 執行緒池
      • 12.1 通過TPL進入執行緒池
        • 12.1.1 Task例外捕獲
      • 12.2 不同過TPL進入執行緒池
        • 12.2.1 QueueUserWorkItem
        • 12.2.2 異步委托
      • 12.3 執行緒池優化
    • 13 代碼
    • 14 參考文章

摘要

執行緒中的概念很多,如果沒有代碼示例來理解,會比較晦澀,而且有些概念落不到實處,因此,本文以一些運行示例代碼,結果來闡述執行緒中的一些基礎概念,讓自己跟讀者一起把執行緒中的概念理解地更深刻,

1 執行緒安全

1.1 未出現執行緒搶占

    class ThreadTest2
    {
        bool done;

        static void Main()
        {
            ThreadTest2 tt = new ThreadTest2();   // Create a common instance
            new Thread(tt.Go).Start();
            tt.Go();
        }
                // Note that Go is now an instance method
        void Go()
        {
                if (!done)
                {
                    done = true;
                    Console.WriteLine("Done");             
                }            
        }
    }

運行結果如下:

Done

1.2 執行緒搶占

    class ThreadTest2
    {
        bool done;

        static void Main()
        {
            ThreadTest2 tt = new ThreadTest2();   // Create a common instance
            new Thread(tt.Go).Start();
            tt.Go();
        }
                // Note that Go is now an instance method
        void Go()
        {
                if (!done)
                {                   
                    Console.WriteLine("Done");        
                    done = true;     
                }            
        }
    }

運行結果如下:

Done
Done

執行緒搶占例子2:

for (int i = 0; i < 10; i++)
  new Thread (() => Console.Write (i)).Start();

運行結果
0223557799

1.3 避免執行緒搶占

    class ThreadTest2
    {
        static readonly object locker = new object();
        bool done;

        static void Main()
        {
            ThreadTest2 tt = new ThreadTest2();   // Create a common instance
            new Thread(tt.Go).Start();
            tt.Go();
        }

        // Note that Go is now an instance method
        void Go()
        {
            lock (locker)
            {
                if (!done)
                {                  
                  Console.WriteLine("Done");
                  done = true;
                }
            }
        }
    }

運行結果如下:

Done

2 執行緒阻塞

    class Program
    {
        static void Main()
        {
            Thread t = new Thread(Go);
            t.Start();
            t.Join();
            Console.WriteLine("Thread t has ended!");
        }

        static void Go()
        {
            for (int i = 0; i < 1000; i++) Console.Write("y");
        }
    }

運行結果:

1000個y列印完畢才輸出"Thread t has ended!",

Thread.Sleep (500);
也會阻塞執行緒,讓渡CPU的執行權給其他執行緒,

3 Thread.yield()和Thread.sleep(0)

sleep(0)效果相當于yield(),會讓當前執行緒放棄剩余時間片,進入相同優先級執行緒佇列的隊尾,只有排在前面的所有同優先級執行緒完成調度后,它才能再次獲執行的機會,

4 執行緒如何作業

多線痛通過內部的執行緒調度器(thread scheduler)管理,通過clr委托作業系統,執行緒調度器會分配適當的執行時間給活動執行緒,執行緒等待(鎖)或者執行緒阻塞(用戶輸入)不會消耗cpu執行時間,
單核處理器電腦上,在Windows,時間片通常會被分配幾十毫秒,遠大于執行緒背景關系切換還時間幾毫秒,
在多處理器計算機上,多執行緒是通過時間片和真正的并發實作的,其中不同的執行緒在不同的CPU上同時運行代碼, 幾乎可以肯定,由于作業系統需要服務自己的執行緒以及其他應用程式的執行緒,因此還會有一定的時間片,
當執行緒的執行由于諸如時間片之類的外部因素而被中斷時,該執行緒被認為是被搶占的, 在大多數情況下,執行緒無法控制其被搶占的時間和地點,

5 執行緒與行程

執行緒與行程有相似之處, 就像行程在計算機上并行運行一樣,多個執行緒在單個行程中并行運行, 行程彼此完全隔離; 執行緒的隔離度有限, 特別是,執行緒與在同一應用程式中運行的其他執行緒共享(堆)記憶體, 這就是為什么執行緒有用的原因:例如,一個執行緒可以在后臺獲取資料,而另一個執行緒可以在資料到達時顯示資料,

6 執行緒的使用和濫用

  • 利于回應式用戶界面
    在同時并行運行的“worker”執行緒上運行耗時的任務,主UI執行緒可以自由繼續處理鍵盤和滑鼠事件,

  • 有效利用原本被阻塞的CPU
    當執行緒正在等待來自另一臺計算機或硬體的回應時,多執行緒很有用, 當一個執行緒在執行任務時被阻塞時,其他執行緒可以利用本來沒有負擔的計算機的其他執行緒來回應任務,

  • 并行編程
    如果以``分而治之''策略在多個執行緒之間共享作業負載,則執行密集計算的代碼可以在多核或多處理器計算機上更快地執行(請參閱第5部分),

  • 隨機執行
    在多核計算機上,有時可以通過預測可能需要完成的事情然后提前進行來提高性能, LINQPad使用此技術來加速新查詢的創建, 一種變化是并行運行許多不同的演算法,這些演算法都可以解決同一任務, 誰先獲得“勝利”,當您不知道哪種演算法執行速度最快時,此方法將非常有效,

  • 允許服務同時處理請求
    在服務器上,客戶端請求可以同時到達,因此需要并行處理(如果使用ASP.NET,WCF,Web服務或遠程處理,.NET Framework會為此自動創建執行緒), 這在客戶端上也很有用(例如,處理對等網路-甚至來自用戶的多個請求),

使用ASP.NET和WCF之類的技術,您如果不知道多執行緒正在發生-除非您在沒有適當鎖定的情況下訪問共享資料(可能通過靜態欄位),會破壞執行緒安全性,

執行緒之間的互動(通常是通過共享資料),會帶來很多復雜性,但卻不可避免,因此,有必要將互動保持在最低限度,并盡可能地堅持簡單可靠的設計,

好的策略是將多執行緒邏輯封裝到可重用的類中,這些類可以獨立檢查和測驗, 框架本身提供了許多更高級別的執行緒結構,我們將在后面介紹,

執行緒化還會在調度和切換執行緒時(如果活動執行緒多于CPU內核)會導致資源和CPU的浪費,并且還會產生創建/釋放成本, 多執行緒并不總是可以加快您的應用程式的速度-如果使用過多或使用不當,它甚至可能減慢其速度, 例如,當涉及大量磁盤I / O時,讓幾個作業執行緒按順序運行任務比一次執行10個執行緒快得多,

7 執行緒傳參

7.1 lambda運算式傳參

最方便的方法就是通過lambda運算式呼叫匿名方法,傳引數,

        static void Main()
        {
            Thread t = new Thread(() =>Print("Hello from t!"));
            t.Start();
        }

        static void Print(string message)
        {
            Console.WriteLine(message);
        }

7.2 執行緒start方法傳參

        static void Main()
        {
            Thread t = new Thread(Print);
            t.Start("Hello from t!");
        }

        static void Print(object messageObj)
        {
            string message = (string)messageObj;   // We need to cast here
            Console.WriteLine(message);
        }

7.3 執行緒創建需要時間

string text = "t1";
Thread t1 = new Thread ( () => Console.WriteLine (text) );
 
text = "t2";
Thread t2 = new Thread ( () => Console.WriteLine (text) );
 
t1.Start();
t2.Start();

運行結果:

t2
t2

以上運行結果說明,在t1執行緒創建之前text被修改成了t2,

8 執行緒命名

每個執行緒都有名稱屬性,目的是為了更方便除錯,

            static void Main()
            {
                Thread.CurrentThread.Name = "main";
                Thread worker = new Thread(Go);
                worker.Name = "worker";
                worker.Start();
                Go();
            }

            static void Go()
            {
                Console.WriteLine("Hello from " + Thread.CurrentThread.Name);
            }

運行結果:

Hello from main
Hello from worker

9 前臺執行緒與后臺執行緒

            Thread worker = new Thread(() => Console.ReadLine());
            if (args.Length > 0) worker.IsBackground = true;
            worker.Name = "backThread";
            worker.Start();
            Console.WriteLine("finish!");

前臺執行緒會隨著主執行緒視窗關閉而停止,后臺執行緒及時主執行緒視窗關閉自己獨立運行,

10 執行緒優先級

執行緒優先級決定了作業系統執行活動執行緒時間的長短,

enum ThreadPriority { Lowest, BelowNormal, Normal, AboveNormal, Highest }

有時候提高了執行緒的優先級,但卻仍然無法滿足一些實時的應用需求,這時候就需要提高行程的優先級,System.Diagnostics命名空間中的process行程類.

using (Process p = Process.GetCurrentProcess())
  p.PriorityClass = ProcessPriorityClass.High;

實際上,ProcessPriorityClass.High比最高優先級低1個級別:Realtime, 將行程優先級設定為Realtime,可指示OS,您永遠不希望該行程將CPU時間浪費在另一個行程上, 如果您的程式進入意外的無限回圈,您甚至可能會發現作業系統已鎖定,只剩下電源按鈕可以拯救您! 因此,高通常是實時應用程式的最佳選擇,

如果您的實時應用程式具有用戶界面,則提高處理優先級將給螢屏更新帶來過多的CPU時間,從而減慢整個計算機的速度(尤其是在UI復雜的情況下), 降低主執行緒的優先級并提高行程的優先級可確保實時執行緒不會因螢屏重繪而被搶占,但不會解決使其他應用程式耗盡CPU時間的問題,因為作業系統仍會分配 整個程序的資源不成比例, 理想的解決方案是使實時作業程式和用戶界面作為具有不同行程優先級的單獨應用程式運行,并通過遠程處理或記憶體映射檔案進行通信, 記憶體映射檔案非常適合此任務, 我們將在C#4.0的第14和25章中簡要介紹它們的作業原理,

11 例外處理

Go無法補捉例外,GoCatch能捕獲當前執行緒的例外,輸出Console.WriteLine("exception.");由此可見,執行緒創建之后,例外只能由本執行緒捕獲,如果其呼叫方需要捕獲,則得用共享記憶體方式往上傳,Task幫我們做了這件事,呼叫方可在task.result里捕獲到其他執行緒的例外,

        public static void Main()
        {
            try
            {
                new Thread(Go).Start();
                Console.ReadKey();
            }
            catch (Exception ex)
            {
                // We'll never get here!
                Console.WriteLine("Exception!");
            }
        }

        static void Go() { throw null; }   // Throws a NullReferenceException

        static void GoCatch()
        {
            try
            {
                // ...
                throw null;    // The NullReferenceException will get caught below
                               // ...
            }
            catch (Exception ex)
            {
                // Typically log the exception, and/or signal another thread
                // that we've come unstuck
                // ...
                Console.WriteLine("exception.");
            }
        }

12 執行緒池

當你創建一個執行緒,幾百毫秒會被花費在例如創建本地私有變數堆疊,每個執行緒都會默認消耗1MB記憶體,從而允許在非常精細的級別上應用多執行緒而不會影響性能,當利用多核處理器以“分而治之”的方式并行執行計算密集型代碼時,這很有用,
執行緒池還限制了將同時運行的作業執行緒總數,活動執行緒過多會限制作業系統的管理負擔,并使CPU快取無效,一旦達到限制,作業將排隊并僅在另一個作業完成時才開始,這使任意并發的應用程式成為可能,例如Web服務器, (異步方法模式是一種先進的技術,通過高效利用池執行緒來進一步實作這一點;我們在C#4.0的第23章中簡要介紹了這一點),
有多種進入執行緒池的方法:
?通過Task Parallel Library(來自Framework 4.0)
?通過呼叫ThreadPool.QueueUserWorkItem
?通過異步委托(await)
?通過BackgroundWorker

以下方法間接使用執行緒池:
?WCF,遠程,ASP.NET和ASMX Web服務應用程式服務器
?System.Timers.Timer和System.Threading.Timer
?以Async結尾的框架方法,例如WebClient(基于事件的異步模式)上的框架方法和大多數BeginXXX方法(異步編程模型模式)
?PLINQ

使用池執行緒時,需要注意以下幾點:
?您無法設定池執行緒的名稱,這會使除錯更加困難(盡管您可以在Visual Studio的“執行緒”視窗中進行除錯時附加說明),
?池執行緒始終是后臺執行緒(這通常不是問題),
?除非您呼叫ThreadPool.SetMinThreads(請參閱優化執行緒池),否則阻塞執行緒池可能會在應用程式的早期階段觸發額外的延遲,
您可以自由更改池執行緒的優先級-將其釋放回池后將恢復為正常狀態,

您可以通過Thread.CurrentThread.IsThreadPoolThread屬性查詢當前是否在執行緒池上執行,

12.1 通過TPL進入執行緒池

通過Task Parallel Library庫中的Task類可輕松使用執行緒池,Task類由Framework 4.0引入,如果你熟悉老的結構,考慮用不帶泛型Task類來替代ThreadPool.QueueUserWorkItem,而泛型Task 代表的是一個異步委托, 新的結構更快,更方便,比老的更靈活,

使用不帶泛型例子的Task類,呼叫Task.Factory.StartNew,傳遞一個目標方法的委托;

        static void Main()    // The Task class is in System.Threading.Tasks
        {
            var task=Task.Factory.StartNew(Go);
            Console.WriteLine("main");

            task.Wait() ;
            Console.WriteLine(task.Result);
            Console.ReadLine();
        }
        static string Go()
        {
            if (Thread.CurrentThread.IsThreadPoolThread)
            { Console.WriteLine("Hello from the thread pool!"); }
            else { Console.WriteLine("Hello just from the thread!"); }
            return "task complete!";
        }

輸出結果:

main
Hello from the thread pool!
task complete!

12.1.1 Task例外捕獲

        static void Main()    // The Task class is in System.Threading.Tasks
        {
            var task=Task.Factory.StartNew(Go);
            Console.WriteLine("main");
            try
            { task.Wait(); }                                   
             catch (Exception e)
            {
                Console.WriteLine("exception!");
            }
            Console.WriteLine(task.Result);
            Console.ReadLine();
        }
        static string Go()
        {
            if (Thread.CurrentThread.IsThreadPoolThread)
            { Console.WriteLine("Hello from the thread pool!"); }
            else { Console.WriteLine("Hello just from the thread!"); }
            throw null;
            return "task complete!";
        }

運行結果,在主執行緒中捕獲到了其他執行緒的例外:

static void Main()
{
  // Start the task executing:
  Task<string> task = Task.Factory.StartNew<string>
    ( () => DownloadString ("http://www.linqpad.net") );
 
  // We can do other work here and it will execute in parallel:
  RunSomeOtherMethod();
 
  // When we need the task's return value, we query its Result property:
  // If it's still executing, the current thread will now block (wait)
  // until the task finishes:
  string result = task.Result;
}
 
static string DownloadString (string uri)
{
  using (var wc = new System.Net.WebClient())
    return wc.DownloadString (uri);
}

Task<string> 就是一個回傳值為string的異步委托,

12.2 不同過TPL進入執行緒池

如果你的框架是.Net 4.0之前的,你可以不通過Task Parallel Library 進入執行緒池,

12.2.1 QueueUserWorkItem

        static void Main()
        {
            ThreadPool.QueueUserWorkItem(Go);
            ThreadPool.QueueUserWorkItem(Go, 123);
            Console.ReadLine();
        }
        static void Go(object data)   // data will be null with the first call.
        {
            Console.WriteLine("Hello from the thread pool! " + data);
        }

運行結果:

Hello from the thread pool!
Hello from the thread pool! 123

與Task不同:

  • 后續執行中無法回傳執行結果;
  • 無法回傳例外給呼叫者;

12.2.2 異步委托

即鄙人寫的這篇文章深入理解C#中的異步(一)——APM模式EAP模式里的2.1APM異步編程模式,
需要補充說明的是:
委托的EndInvoke 做了3件事:

  • 阻塞等待;
  • 回傳結果;
  • 向呼叫者跑出例外;

2.1.3 為異步委托的回呼例子

12.3 執行緒池優化

執行緒池從其池中的一個執行緒開始, 分配任務后,池管理器會“注入”新執行緒以應對額外的并發作業負載(最大限制), 在足夠長時間的不活動之后,如果池管理器懷疑這樣做會導致更好的吞吐量,則可以“退出”執行緒,
您可以通過呼叫ThreadPool.SetMaxThreads;來設定池將創建的執行緒的上限; 默認值為:
?32位環境中的Framework 4.0中的1023
?64位環境中的Framework 4.0中的32768
?Framework 3.5中的每個內核250個
?Framework 2.0中每個內核25個

您還可以通過呼叫ThreadPool.SetMinThreads設定下限, 下限的作用是微妙的:這是一種高級優化技術,它指示池管理器在達到下限之前不要延遲執行緒的分配, 當存在阻塞的執行緒時,提高最小執行緒數可提高并發性,
默認的下限是每個處理器內核一個執行緒-允許全部CPU利用率的最小值, 但是,在服務器環境(例如IIS下的ASP .NET)上,下限通常要高得多-多達50個或更多,
設定執行緒池最小執行緒數量,

ThreadPool.SetMinThreads (50, 50);

13 代碼

本文代碼git下載

14 參考文章

Threading in C#


著作權宣告:本文為博主翻譯文章+自己理解,部分代碼自己寫,遵循 CC 4.0 BY-SA 著作權協議,轉載請附上原文出處鏈接和本宣告, 本文鏈接:https://www.cnblogs.com/JerryMouseLi/p/14135600.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/234532.html

標籤:.NET Core

上一篇:2020年總結-用學習過的技術搭建一個簡單的微服務框架 + 原始碼

下一篇:.Net5.0 WebApi 注冊登錄以及基于JWT的簡單身份認證與授權

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more