主頁 > .NET開發 > 多執行緒之旅(Task 任務)

多執行緒之旅(Task 任務)

2020-09-16 03:56:11 .NET開發

一、Task(任務)和ThreadPool(執行緒池)不同

      原始碼

  1、執行緒(Thread)是創建并發工具的底層類,但是在前幾篇文章中我們介紹了Thread的特點,和實體,可以很明顯發現局限性(回傳值不好獲取(必須在一個作用域中)),當我們執行緒執行完之后不能很好的進行下一次任務的執行,需要多次銷毀和創建,所以不是很容易使用在多并發的情況下,

  2、執行緒池(ThreadPool) QueueUserWorkItem是很容易發起并發任務,也解決了上面我們的需要多次創建、銷毀的性能損耗解決了,但是我們就是太簡單的,我不知道執行緒什么時候結束,也沒有獲取回傳值的途徑,也是比較尷尬的事情,

  3、任務(Task)表示一個通過或不通過執行緒實作的并發操作,任務是可組合的,使用延續(continuation)可將它們串聯在一起,它們可以使用執行緒池減少啟動延遲,可使用回呼方法避免多個執行緒同時等待I/O密集操作,

二、初識Task(任務)

  1、Task(任務)是在.NET 4.0引入的、Task是在我們執行緒池ThreadPool上面進行進一步的優化,所以Task默認還是執行緒池執行緒,并且是后臺執行緒,當我們的主執行緒結束時其他執行緒也會結束

  2、Task創建任務,也和之前差不多

 /// <summary>
        /// Task 的使用
        /// Task 的創建還是差不多的
        /// </summary>
        public static void Show()
        {
            //實體方式
            Task task = new Task(() =>
            {
                Console.WriteLine("無回傳引數的委托");
            });

            //無參有回傳值
            Task<string> task1 = new Task<string>(() =>
            {
                return "我是回傳值";
            });

            //有參有回傳值
            Task<string> task2 = new Task<string>(x =>
            {
                return "回傳值 -- " + x.ToString();
            }, "我是輸入引數");
            //開啟執行緒
            task2.Start();
            //獲取回傳值 Result會堵塞執行緒獲取回傳值
            Console.WriteLine(task2.Result);

            //使用執行緒工廠創建 無引數無回傳值執行緒
            Task.Factory.StartNew(() =>
            {
                Console.WriteLine("這個是執行緒工廠創建");
            }).Start();

            //使用執行緒工廠創建 有引數有回傳值執行緒
            Task.Factory.StartNew(x =>
            {
                return "回傳值 -- " + x.ToString(); ;
            }, "我是引數");

            //直接靜態方法運行
            Task.Run(() =>
            {
                Console.WriteLine("無回傳引數的委托");
            });
        }
View Code

說明

  1、事實上Task.Factory型別本身就是TaskFactory(任務工廠),而Task.Run(在.NET4.5引入,4.0版本呼叫的是后者)是Task.Factory.StartNew的簡寫法,是后者的多載版本,更靈活簡單些,

  2、呼叫靜態Run方法會自動創建Task物件并立即呼叫Start

  3、Task.Run等方式啟動任務并沒有呼叫Start,因為它創建的是“熱”任務,相反“冷”任務的創建是通過Task建構式,

三、Task(任務進階)

  1、Wait 等待Task執行緒完成才會執行后續動作

 //創建一個執行緒使用Wait堵塞執行緒
            Task.Run(() =>
            {
                Console.WriteLine("Wait 等待Task執行緒完成才會執行后續動作");
            }).Wait();
View Code

  2、WaitAll 等待Task[] 執行緒陣列全部執行成功之后才會執行后續動作

            //創建一個裝載執行緒的容器
            List<Task> list = new List<Task>();
            for (int i = 0; i < 10; i++)
            {
                list.Add(Task.Run(() =>
                {
                    Console.WriteLine("WaitAll 執行");
                }));
            }
            Task.WaitAll(list.ToArray());
            Console.WriteLine("Wait執行完畢");
View Code

  3、WaitAny 等待Task[] 執行緒陣列任一執行成功之后就會執行后續動作

//創建一個裝載執行緒的容器
            List<Task> list = new List<Task>();
            for (int i = 0; i < 10; i++)
            {
                list.Add(Task.Run(() =>
                {
                    Console.WriteLine("WaitAny 執行");
                }));
            }
            Task.WaitAny(list.ToArray());
            Console.WriteLine("WaitAny 執行完畢");
View Code

  4、WhenAll 等待Task[] 執行緒陣列全部執行成功之后才會執行后續動作、與WaitAll不同的是他有回呼函式ContinueWith

 //創建一個裝載執行緒的容器
            List<Task> list = new List<Task>();
            for (int i = 0; i < 10; i++)
            {
                list.Add(Task.Run(() =>
                {
                    Console.WriteLine("WhenAll 執行");
                }));
            }
            Task.WhenAll(list.ToArray()).ContinueWith(x =>
            {
                return x.AsyncState;
            });
            Console.WriteLine("WhenAll 執行完畢");
View Code

  5、WhenAny 等待Task[] 執行緒陣列任一執行成功之后就會執行后續動作、與WaitAny不同的是他有回呼函式ContinueWith

//創建一個裝載執行緒的容器
            List<Task> list = new List<Task>();
            for (int i = 0; i < 10; i++)
            {
                list.Add(Task.Run(() =>
                {
                    Console.WriteLine("WhenAny 執行");
                }));
            }
            Task.WhenAny(list.ToArray()).ContinueWith(x =>
            {
                return x.AsyncState;
            });
            Console.WriteLine("WhenAny 執行完畢");
            Console.ReadLine();
View Code

四、Parallel 并發控制

  1、是在Task的基礎上做了封裝 4.5,使用起來比較簡單,如果我們執行100個任務,只能用到10個執行緒我們就可以使用Parallel并發控制

        public static void Show5()
        {
            //第一種方法是
            Parallel.Invoke(() =>
            {
                Console.WriteLine("我是執行緒一號");
            }, () =>
            {
                Console.WriteLine("我是執行緒二號");
            }, () =>
            {
                Console.WriteLine("我是執行緒三號");
            });

            //for 方式創建多執行緒
            Parallel.For(0, 5, x =>
            {
                Console.WriteLine("這個看名字就知道是for了哈哈 i=" + x);
            });

            //ForEach 方式創建多執行緒
            Parallel.ForEach(new string[] { "0", "1", "2", "3", "4" }, x => Console.WriteLine("這個看名字就知道是ForEach了哈哈 i=" + x));

            //這個我們包一層,就不會卡主界面了
            Task.Run(() =>
            {
                //創建執行緒選項
                ParallelOptions parallelOptions = new ParallelOptions()
                {
                    MaxDegreeOfParallelism = 3
                };
                //創建一個并發執行緒
                Parallel.For(0, 5, parallelOptions, x =>
                {
                    Console.WriteLine("限制執行的次數");
                });
            }).Wait();
            Console.WriteLine("**************************************");

            //Break  Stop  都不推薦用
            ParallelOptions parallelOptions = new ParallelOptions();
            parallelOptions.MaxDegreeOfParallelism = 3;
            Parallel.For(0, 40, parallelOptions, (i, state) =>
            {
                if (i == 20)
                {
                    Console.WriteLine("執行緒Break,Parallel結束");
                    state.Break();//結束Parallel
                                  //return;//必須帶上
                }
                if (i == 2)
                {
                    Console.WriteLine("執行緒Stop,當前任務結束");
                    state.Stop();//當前這次結束
                                 //return;//必須帶上
                }
                Console.WriteLine("我是執行緒i=" + i);
            });
        }
View Code

 五、多執行緒實體

  1、代碼例外我資訊大家都不陌生,比如我剛剛寫代碼經常會報 =>物件未定義null  的真的是讓我心痛了一地,那我們的多執行緒中怎么去處理代碼例外呢? 和我們經常寫的同步方法不一樣,同步方法遇到錯誤會直接拋出,當是如果我們的多執行緒中出現代碼例外,那么這個例外會自動傳遞呼叫Wait 或者 Task<TResult> 的Result屬性上面,任務的例外會將自動捕獲并且拋給呼叫者,為了確保報告所有的例外,CLR會將例外封裝到AggregateExcepiton容器中,這容器是公開了InnerExceptions屬性中包含所有捕獲的例外,但是如果我們的執行緒沒有等待結束不會獲取到例外,

class Program
      {
         static void Main(string[] args)
         {
              try
             {
                  Task.Run(() =>
                  {
                      throw new Exception("錯誤");
                 }).Wait();
             }
             catch (AggregateException axe)
             {
                 foreach (var item in axe.InnerExceptions)
                 {
                     Console.WriteLine(item.Message);
                 }
            }
             Console.ReadKey();
         }
     }
View Code
 /// <summary>
        /// 多執行緒捕獲例外 
        /// 多執行緒會將我們的例外吞了,因為我們的執行緒執行會直接執行完代碼,不會去等待你捕獲到我的例外,
        /// 我們的執行緒中最好是不要出現例外,自己處理好,
        /// </summary>
        public static void Show()
        {
            //創建一個多執行緒工廠
            TaskFactory taskFactory = new TaskFactory();
            //創建一個多執行緒容器
            List<Task> tasks = new List<Task>();
            //創建委托
            Action action = () =>
            {
                try
                {
                    string str = "sad";
                    int num = int.Parse(str);
                }
                catch (AggregateException ax)
                {
                    Console.WriteLine("我是AggregateException 我抓到了例外啦 ax:" + ax);
                }
                catch (Exception)
                {
                    Console.WriteLine("我是執行緒我已經報錯了");
                }
            };
            //這個是我們經常需要做的捕獲例外
            try
            {
                //創建10個多執行緒
                for (int i = 0; i < 10; i++)
                {
                    tasks.Add(taskFactory.StartNew(action));
                }
                Task.WaitAll(tasks.ToArray());
            }
            catch (Exception ex)
            {
                Console.WriteLine("例外啦");
            }
            Console.WriteLine("我已經執行完了");
        }
View Code

  2、多執行緒取消機制,我們的Task在外部無法進行暫停 Thread().Abort() 無法很好控制,上上篇中Thread我們也講到了Thread().Abort() 的不足之處,有問題就有解決方案,如果我們使用一個全域的變數控制,就需要不斷的監控我們的變數取消執行緒,那么說當然有對應的方法啦,CancellationTokenSource (取消標記源)我們可以創建一個取消標記源,我們在創建執行緒的時候傳入我們取消標記源Token,Cancel()方法 取消執行緒,IsCancellationRequested 回傳一個bool值,判斷是不是取消了執行緒了,

 /// <summary>
        /// 多執行緒取消機制 我們的Task在外部無法進行暫停 Thread().Abort() 無法很好控制,我們的執行緒,
        /// 如果我們使用一個全域的變數控制,就需要不斷的監控我們的變數取消執行緒,
        /// 我們可以創建一個取消標記源,我們在創建執行緒的時候傳入我們取消標記源Token
        /// Cancel() 取消執行緒,IsCancellationRequested 回傳一個bool值,判斷是不是取消了執行緒了
        /// </summary>
        public static void Show1()
        {
            //創建一個取消標記源
            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
            //創建一個多執行緒工廠
            TaskFactory taskFactory = new TaskFactory();
            //創建一個多執行緒容器
            List<Task> tasks = new List<Task>();
            //創建委托
            Action<object> action = x =>
            {
                try
                {
                    //每個執行緒我等待2秒鐘,不然
                    Thread.Sleep(2000);
                    //判斷是不是取消執行緒了
                    if (cancellationTokenSource.IsCancellationRequested)
                    {
                        Console.WriteLine("放棄執行后面執行緒");
                        return;
                    }
                    if (Convert.ToUInt32(x) == 20)
                    {
                        throw new Exception(string.Format("{0} 執行失敗", x));
                    }
                    Console.WriteLine("我是正常的我在執行");
                }
                catch (AggregateException ax)
                {
                    Console.WriteLine("我是AggregateException 我抓到了例外啦 ax:" + ax);
                }
                catch (Exception ex)
                {
                    //例外出現取消后面執行的所有執行緒
                    cancellationTokenSource.Cancel();
                    Console.WriteLine("我是執行緒我已經報錯了");
                }
            };
            //這個是我們經常需要做的捕獲例外
            try
            {
                //創建10個多執行緒
                for (int i = 0; i < 50; i++)
                {
                    int k = i;
                    tasks.Add(taskFactory.StartNew(action, k, cancellationTokenSource.Token));
                }
                Task.WaitAll(tasks.ToArray());
            }
            catch (Exception ex)
            {
                Console.WriteLine("例外啦");
            }
            Console.WriteLine("我已經執行完了");
        }
View Code

  3、多執行緒創建臨時變數,當我們啟動執行緒之后他們執行沒有先后快慢之分,正常的回圈中的變數也沒有作用,這個時候就要創建一個臨時變數存盤資訊,解決不訪問一個資料源,

 /// <summary>
        /// 執行緒臨時變數
        /// </summary>
        public static void Show2()
        {
            //創建一個執行緒工廠
            TaskFactory taskFactory = new TaskFactory();
            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
            //創建一個委托
            Action<object> action = x =>
            {
                Console.WriteLine("傳入引數 x:" + x);
            };
            for (int i = 0; i < 20; i++)
            {
                //這最主要的就是會創建20個k的臨時變數
                int k = i;
                taskFactory.StartNew(action, k);
            }
            Console.ReadLine();
        }
View Code

 

   4、多執行緒鎖,之前我們有提到過我們的多執行緒可以同時公共資源,如果我們有個變數需要加一,但是和這個時候我們有10個執行緒同時操作這個會怎么樣呢?

        public static List<int> list = new List<int>();
        public static int count = 0;

        public static void Show3()
        {
            //創建執行緒容器
            List<Task> tasks = new List<Task>();
            for (int i = 0; i < 10000; i++)
            {
                //添加執行緒
                tasks.Add(Task.Run(() =>
                {
                        list.Add(i);
                        count++;
                }));
            }
            Task.WaitAll(tasks.ToArray());
            Console.WriteLine("list 行數:" + list.Count + " count 總數:" + count);
            Console.ReadLine();
        }

 我們上面的代碼本來是count++到10000,但是我們看到結果的時候,我們是不是傻了呀,怎么是不是說好的10000呢,其實的資料讓狗吃了?真的是小朋友有很多問號??????

 

  5、那么我們要怎么去解決這個問題呢?方法還是有的今天我們要將到一個語法糖lock、它能做什么呢?它相當于一個代碼塊鎖,它主要鎖的是一個物件,當它鎖住物件的時候會當其他執行緒發生堵塞,因為當它鎖住代碼時候也是鎖住了物件的訪問鏈,是其他的執行緒不能訪問,必須等待物件訪問鏈被釋放之后才能被一個執行緒訪問,我們的使用lock鎖代碼塊的時候,盡量減少鎖入代碼塊范圍,因為我們鎖代碼之后會導致只有一個執行緒可以拿到資料,盡量只要必須使用lock的地方使用,

  6、Lock使用要注意的地方

      1、lock只能鎖參考型別的物件.

    2、不能鎖空物件null某一物件可以指向Null,但Null是不需要被釋放的,(請參考:認識全面的null),

    3、lock 盡量不要去鎖string 型別雖然它是參考型別,但是string是享元模式,字串型別被CLR“暫留”
這意味著整個程式中任何給定字串都只有一個實體,就是這同一個物件表示了所有運行的應用程式域的所有執行緒中的該文本,因此,只要在應用程式行程中的任何位置處具有相同內容的字串上放置了鎖,就將鎖定應用程式中該字串的所有實體,因此,最好鎖定不會被暫留的私有或受保護成員,

    4、lock就避免鎖定public 型別或不受程式控制的物件,例如,如果該實體可以被公開訪問,則 lock(this) 可能會有問題,因為不受控制的代碼也可能會鎖定該物件,這可能導致死鎖,即兩個或更多個執行緒等待釋放同一物件,出于同樣的原因,鎖定公共資料型別(相比于物件)也可能導致問題,

 /// <summary>
        /// 創建一個靜態物件,主要是用于鎖代碼塊,如果是靜態的就會全域鎖,如果要鎖實體類,就不使用靜態就好了
        /// </summary>
        private readonly static object obj = new object();
        public static List<int> list = new List<int>();
        public static int count = 0;
        /// <summary>
        /// lock 多執行緒鎖
        /// 當我們的執行緒訪問同一個全域變數、同時訪問同一個區域變數、同一個檔案夾,就會出現執行緒不安全
        /// 我們的使用lock鎖代碼塊的時候,盡量減少鎖入代碼塊范圍,因為我們鎖代碼之后會導致只有一個執行緒可以
        /// 訪問到我們代碼塊了
        /// </summary>
        public static void Show3()
        {
            //創建執行緒容器
            List<Task> tasks = new List<Task>();
            //鎖代碼
            for (int i = 0; i < 10000; i++)
            {
                //添加執行緒
                tasks.Add(Task.Run(() =>
                {
                    //鎖代碼
                    lock (obj)
                    {
                        //這個里面就只會出現一個執行緒訪問,資源,
                        list.Add(i);
                        count++;
                    }
                    //lock 是一個語法糖,就是下面的代碼
                    Monitor.Enter(obj);

                    Monitor.Exit(obj);
                }));
            }
            Task.WaitAll(tasks.ToArray());
            Console.WriteLine("list 行數:" + list.Count + " count 總數:" + count);
            Console.ReadLine();
        }

7、總結實體篇,雙色球實體,

  1、雙色球:投注號碼由6個紅色球號碼和1個藍色球號碼組成,紅色球號碼從01--33中選擇(不重復)藍色球號碼從01--16中選擇(可以跟紅球重復),代碼我已經實作了大家可以下載原始碼,只有自己多多倒騰才能讓自己的技術成長, 下一次我們async和await這兩個關鍵字下篇記錄

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

標籤:C#

上一篇:關鍵詞匹配優化(第0篇)—— 問題和思路

下一篇:當模板方法遇到了委托函式,你的代碼又可以精簡了

標籤雲
其他(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