<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      并發(fā)編程 - 線程淺試

      前面已經(jīng)對線程有了初步認(rèn)識,下面我們來嘗試使用線程。

      01、線程創(chuàng)建

      在C#中創(chuàng)建線程主要是通過Thread構(gòu)造函數(shù)實現(xiàn),下面講解3種常見的創(chuàng)建方式。

      1、通過ThreadStart創(chuàng)建

      Thread有一個帶有ThreadStart類型參數(shù)的構(gòu)造函數(shù),其中參數(shù)ThreadStart是一個無參無返回值委托,因此我們可以創(chuàng)建一個無參無返回值方法傳入Thread構(gòu)造函數(shù)中,代碼如下:

      public class ThreadSample
      {
          public static void CreateThread()
          {
              Console.WriteLine($"主線程Id:{Thread.CurrentThread.ManagedThreadId}");
              var thread = new Thread(BusinessProcess);
              thread.Start();
          }
          //線程1
          public static void BusinessProcess()
          {
              Console.WriteLine($"BusinessProcess 線程Id:{Thread.CurrentThread.ManagedThreadId}");
              Console.WriteLine("開始處理業(yè)務(wù)……");
              //業(yè)務(wù)實現(xiàn)
              Console.WriteLine("結(jié)束處理業(yè)務(wù)……");
          }
      }
      

      代碼也相當(dāng)簡單,我們在主線程中通過Thread創(chuàng)建了一個新的線程用來運行BusinessProcess方法,同時通過Thread.CurrentThread.ManagedThreadId打印出當(dāng)前線程Id。

      代碼執(zhí)行結(jié)果如下,主線程Id和業(yè)務(wù)線程Id并不相同。

      2、通過ParameterizedThreadStart帶參創(chuàng)建

      Thread還有一個帶有ParameterizedThreadStart類型參數(shù)的構(gòu)造函數(shù),其中參數(shù)ParameterizedThreadStart是一個有參無返回值委托,其中參數(shù)為object類型,因此我們可以創(chuàng)建一個有參無返回值方法傳入Thread構(gòu)造函數(shù)中,然后通過Thread.Start方法把參數(shù)傳遞給線程,代碼如下:

      public static void CreateThreadParameterized()
      {
          Console.WriteLine($"主線程Id:{Thread.CurrentThread.ManagedThreadId}");
          var thread = new Thread(BusinessProcessParameterized);
          //傳入?yún)?shù)
          thread.Start("Hello World!");
      }
      //帶參業(yè)務(wù)線程
      public static void BusinessProcessParameterized(object? param)
      {
          Console.WriteLine($"BusinessProcess 線程Id:{Thread.CurrentThread.ManagedThreadId}");
          Console.WriteLine($"參數(shù) param 為:{param}");
          Console.WriteLine("開始處理業(yè)務(wù)……");
          //業(yè)務(wù)實現(xiàn)
          Console.WriteLine("結(jié)束處理業(yè)務(wù)……");
      }
      

      我們看看代碼執(zhí)行結(jié)果:

      該方式有個限制,因為ParameterizedThreadStart委托參數(shù)為object類型,因此我們的業(yè)務(wù)方法也必須要用object類型接收參數(shù),然后再根據(jù)實際類型進行轉(zhuǎn)換。

      3、通過Lambda表達式創(chuàng)建

      通過上面可以知道無論ThreadStart還是ParameterizedThreadStart本質(zhì)上都是一個委托,因此我們可以直接使用Lambda表達式直接構(gòu)建一個委托??梢钥纯匆韵麓a:

      public static void CreateThreadLambda()
      {
          Console.WriteLine($"主線程Id:{Thread.CurrentThread.ManagedThreadId}");
          var thread = new Thread(() =>
          {
              Console.WriteLine($"業(yè)務(wù)線程Id:{Thread.CurrentThread.ManagedThreadId}");
              Console.WriteLine("開始處理業(yè)務(wù)……");
              //業(yè)務(wù)實現(xiàn)
              Console.WriteLine("結(jié)束處理業(yè)務(wù)……");
          });
          //傳入?yún)?shù)
          thread.Start();
      }
      

      代碼執(zhí)行結(jié)果如下:

      因為Lambda表達式可以直接訪問外部作用域中的變量,因此線程傳參還可以使用Lambda表達式來實現(xiàn)。

      但是這也導(dǎo)致了一些問題,比如下面代碼執(zhí)行結(jié)果應(yīng)該是什么?先自己想想看。

      public static void CreateThreadLambdaParameterized()
      {
          Console.WriteLine($"主線程Id:{Thread.CurrentThread.ManagedThreadId}");
          var param = "Hello";
          var thread1 = new Thread(() => BusinessProcessParameterized(param));
          thread1.Start();
          param = "World";
          var thread2 = new Thread(() => BusinessProcessParameterized(param));
          thread2.Start();
      }
      //帶參業(yè)務(wù)線程
      public static void BusinessProcessParameterized(string param)
      {
          Console.WriteLine($"業(yè)務(wù)線程Id:{Thread.CurrentThread.ManagedThreadId}");
          Console.WriteLine($"參數(shù) param 為:{param}");
      }
      

      看看執(zhí)行結(jié)果:

      和你想想的結(jié)果一樣嗎?

      這是因為當(dāng)在Lambda 表達式中使用任何外部局部變量時,編譯器會自動生成一個類,并將該變量作為該類的一個屬性。因此這些外部變量并不是存儲在棧中,而是通過引用存儲在堆中,因此此時param參數(shù)實際上在內(nèi)存中是一個類是一個引用類型,所以兩個線程中使用的param都指向了堆中的同一個值。

      并且使用Lambda表達式引用另一個C#對象的方式有個專有名詞叫閉包。感興趣的可以去了解下閉包概念。

      02、線程休眠

      可以通過Sleep方法暫停當(dāng)前線程,使其處于休眠狀態(tài),以盡可能少的占用CPU時間??慈缦率纠a,通過在Sleep方法前后打印出當(dāng)前時間對比,來觀察暫停線程效果。

      public static void ThreadSleep()
      {
          Console.WriteLine($"主線程Id:{Thread.CurrentThread.ManagedThreadId}");
          var thread = new Thread(() =>
          {
              Console.WriteLine($"業(yè)務(wù)線程Id:{Thread.CurrentThread.ManagedThreadId}");
              Console.WriteLine($"暫停線程前:{DateTime.Now:HH:mm:ss}");
              //暫停線程10秒
              Thread.Sleep(10000);
              Console.WriteLine($"暫停線程后:{DateTime.Now:HH:mm:ss}");
          });
          thread.Start();
          thread.Join();
      }
      

      代碼執(zhí)行結(jié)果如下:

      可以發(fā)現(xiàn)暫停線程前后正好差了10秒鐘。

      03、線程等待

      線程等待指讓程序等待另一個需要長時間計算的線程運行完成后,再繼續(xù)后面操作。而使用Thread.Sleep方法并不能滿足需求,因為當(dāng)前并不知道執(zhí)行計算到底需要多少時間,因此可以使用Thread.Join。如上一小節(jié)中代碼,當(dāng)代碼執(zhí)行到Thread.Join方法時,則線程會處于阻塞狀態(tài),只有線程執(zhí)行完成后才會繼續(xù)往下執(zhí)行。具體示例可以看上一小節(jié)。

      04、線程其他方法

      此外線程還有暫停、恢復(fù)、中斷、終止等線程方法,這里就不介紹了,因為一些方法已經(jīng)棄用沒有必要再花經(jīng)歷學(xué)習(xí)了。

      05、異常處理

      對于線程中的異常需要特別注意,對于一個Thread子線程所產(chǎn)生的異常,默認(rèn)情況下主線程并不能捕捉到,可以查看下面示例:

      public static void ThreadException()
      {
          Console.WriteLine($"主線程Id:{Thread.CurrentThread.ManagedThreadId}");
          try
          {
              var thread = new Thread(ThreadThrowException);
              thread.Start();
          }
          catch (Exception ex)
          {
              Console.WriteLine("子線程異常信息:" + ex.Message);
          }
      }
      //業(yè)務(wù)線程不處理異常,直接拋出
      public static void ThreadThrowException()
      {
          Console.WriteLine($"業(yè)務(wù)線程Id:{Thread.CurrentThread.ManagedThreadId}");
          Console.WriteLine("開始處理業(yè)務(wù)……");
          //業(yè)務(wù)實現(xiàn)
          Console.WriteLine("結(jié)束處理業(yè)務(wù)……");
          throw new Exception("異常");
      }
      

      運行結(jié)果如下:

      可以看到在主線程中并沒有捕捉到子線程拋出的異常,而導(dǎo)致程序直接中斷。因此我們在處理線程異常時需要特別注意,可以直接在線程中處理異常。

      06、何時應(yīng)該使用線程

      線程有很多優(yōu)點,但也并不是萬能的,因為每一個線程都會產(chǎn)生大量的資源消耗,包括:占用大量內(nèi)存空間,線程的創(chuàng)建、銷毀和管理,線程之間的上下文切換,以及垃圾回收的消耗。

      舉個簡單例子,比如一個小餐館,有一個廚師,一個下單員,客戶下單給下單員,下單員把客戶下的菜單傳遞給廚師。假如現(xiàn)在客戶很多一個下單員忙不過來,老板決定再添加一個下單員,此時下單的效率可以提升一倍,但是廚師還是一個,那么就會導(dǎo)致當(dāng)廚師和A下單員交接的時候,B下單員只能等著,并且因為之前廚師和A下單員長時間合作形成了彼此默契,這是再和B下單員交接的時候效率可能并不高,因此最終整體效率并不一定提升多少。如果把廚師比作CPU處理器,下單員比作線程,如果要想餐館的整體效率提升那么在增加下單員的時候,必須要相應(yīng)的添加廚師,才能使得餐館最大效率的提升。

      因此并不是說無腦的添加線程就可以使得程序效率提升,需要按需使用。

      比如在以下使用場景可以考慮使用多線程:文件多寫、網(wǎng)絡(luò)請求、數(shù)據(jù)庫查詢、圖像處理、數(shù)據(jù)分析、定時任務(wù)等。

      :測試方法代碼以及示例源碼都已經(jīng)上傳至代碼庫,有興趣的可以看看。https://gitee.com/hugogoos/Planner

      posted @ 2025-01-17 18:02  IT規(guī)劃師  閱讀(914)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲成人av综合一区| 在线播放深夜精品三级| 成人午夜免费无码视频在线观看| 亚洲一区二区三区啪啪| 男人扒开添女人下部免费视频| 久久精品国产热久久精品国产亚洲 | 欧美野外伦姧在线观看| 蜜臀av一区二区精品字幕| 久久天天躁夜夜躁狠狠85| 东京热大乱系列无码| 阿尔山市| 精品少妇av蜜臀av| 亚洲性日韩精品一区二区| 人妻系列无码专区免费| 一本色道国产在线观看二区| 亚洲中文字幕无码不卡电影| 泰和县| 亚洲色偷偷偷网站色偷一区 | 国产午夜91福利一区二区| 国内精品视频一区二区三区| 国产精品大片中文字幕| 国产精品久久久久影院色| 国产三级国产精品国产专| 日韩国产精品中文字幕| 义马市| 色偷偷女人的天堂亚洲网| 国产精品 无码专区| 欧美亚洲一区二区三区在线| 久久亚洲精品成人av秋霞| 久久成人国产精品免费软件| 人妻少妇看a偷人无码| 国产欧美综合在线观看第十页| 狠狠色狠狠色综合日日不卡| 亚洲成aⅴ人片久青草影院| 日韩精品一区二区都可以| 亚洲人妻系列中文字幕| 国产午夜成人无码免费看| 国产成人亚洲精品成人区| 在线欧美精品一区二区三区| 激情五月天一区二区三区| 国产又色又爽无遮挡免费动态图|