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

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

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

      C#多線程編程(一)進程與線程

      一、 進程

              簡單來說,進程是對資源的抽象,是資源的容器,在傳統操作系統中,進程是資源分配的基本單位,而且是執行的基本單位,進程支持并發執行,因為每個進程有獨立的數據,獨立的堆??臻g。一個程序想要并發執行,開多個進程即可。

      Q1:在單核下,進程之間如何同時執行?

              首先要區分兩個概念——并發和并行

      • 并發:并發是指在一段微小的時間段中,有多個程序代碼段被CPU執行,宏觀上表現出來就是多個程序能”同時“執行。
      • 并行:并行是指在一個時間點,有多個程序段代碼被CPU執行,它才是真正的同時執行。

              所以應該說進程之間是并發執行。對于CPU來講,它不知道進程的存在,CPU主要與寄存器打交道。有一些常用的寄存器,如程序計數器寄存器,這個寄存器存儲了將要執行的指令的地址,這個寄存器的地址指向哪,CPU就去哪。還有一些堆棧寄存器和通用寄存器等等等,總之,這些數據構成了一個程序的執行環境,這個執行環境就叫做”上下文(Context)“,進程之間切換本質就是保存這些數據到內存,術語叫做”保存現場“,然后恢復某個進程的執行環境,也即是”恢復現場“,整個過程術語叫做“上下文切換”,具體點就是進程上下文切換,這就是進程之間能并發執行的本質——頻繁的切換進程上下文。這個功能是由操作系統提供的,是內核態的,對應用軟件開發人員透明。

      二、 線程

              進程雖然支持并發,但是對并發不是很友好,不友好是指每開啟一個進程,都要重新分配一部分資源,而線程相對進程來說,創建線程的代價比創建進程要小,所以引入線程能更好的提高并發性。在現代操作系統中,進程變成了資源分配的基本單位,而線程變成了執行的基本單位,每個線程都有獨立的堆棧空間,同一個進程的所有線程共享代碼段和地址空間等共享資源。相應的上下文切換從進程上下文切換變成了線程上下文切換。

      三、 為什么要引入進程和線程

      1. 提高CPU利用率,在早期的單道批處理系統中,如果執行中的代碼需要依賴與外部條件,將會導致CPU空閑,例如文件讀取,等待鍵盤信號輸入,這將浪費大量的CPU時間。引入多進程和線程可以解決CPU利用率低這個問題。
      2. 隔離程序之間的數據(每個進程都有單獨的地址空間),保證系統運行的穩定性。
      3. 提高系統的響應性和交互能力。

      四、 在C#中創建托管線程

            補充:之所以叫托管線程是因為CLR需要屏蔽操作系統線程的細節,這樣可以更好的跨平臺使用,所以一個托管線程不一定總在一個操作系統級別上的線程上執行,換言之一個托管線程可能在多個“本機線程上執行”,但是托管線程是一樣的,從托管線程的ID可知。

      1. Thread類

             在.NET中,托管線程分為:

      • 前臺線程
      • 后臺線程

            一個.Net程序中,至少要有一個前臺線程,所有前臺線程結束了,所有的后臺線程將會被公共語言運行時(CLR)強制銷毀,程序執行結束。

            如下將在控制臺程序中創建一個后臺線程

       1 static void Main(string[] args)
       2 {
       3      var t = new Thread(() =>
       4      {
       5          Thread.Sleep(1000);
       6          Console.WriteLine("執行完畢");
       7      });
       8     t.IsBackground = true;
       9      t.Start();
      10 }
      View Code


      image

            主線程(默認是前臺線程)執行完畢,程序直接退出。

      image

            但IsBackground 屬性改為false時,控制臺會打印“執行完畢”。

      2. 有什么問題

            直接使用Thread類來進行多線程編程浪費資源(服務器端更加明顯)且不方便,舉個栗子。

            假如我寫一個Web服務器程序,每個請求創建一個線程,那么每一次我都要new一個Thread對象,然后傳入處理HttpRequest的委托,處理完之后,線程將會被銷毀,這將會導致浪費大量CPU時間和內存,在早期CPU性能不行和內存資源珍貴的情況下這個缺點會被放大,在現在這個缺點不是很明顯,原因是硬件上來了。

            不方便體現在哪呢?

      • 無法直接獲取另一個線程內未被捕捉的異常
      • 無法直接獲取線程函數的返回值


       1 public static void ThrowException()
       2 {
       3      throw new Exception("發生異常");
       4 }
       5 static void Main(string[] args)
       6 {
       7      var t = new Thread(() =>
       8      {
       9          Thread.Sleep(1000);
      10          ThrowException();
      11      });
      12     t.IsBackground = false;
      13      try
      14      {
      15          t.Start();
      16      }
      17      catch(Exception e)
      18      {
      19          Console.WriteLine(e.Message);
      20      }
      21 }
      View Code


            上述代碼將會導致程序奔潰,如下圖。


      image

            要想直接獲取返回值和可以直接從主線程捕捉線程函數內未捕捉的異常,我們可以這么做。

            新建一個MyTask.cs文件,內容如下

       1 using System;
       2 using System.Threading;
       3 namespace ConsoleApp1
       4 {
       5      public class MyTask
       6      {
       7          private Thread _thread;
       8          private Action _action;
       9          private Exception _innerException;
      10         public MyTask()
      11          {
      12         }
      13          public MyTask(Action action)
      14          {
      15              _action = action;
      16          }
      17          protected virtual void Excute()
      18          {
      19              try
      20              {
      21                  _action();
      22              }
      23              catch(Exception e)
      24              {
      25                  _innerException = e;
      26              }
      27       
      28          }
      29          public void Start()
      30          {
      31              if (_thread != null) throw new InvalidOperationException("任務已經開始");
      32              _thread = new Thread(() => Excute());
      33              _thread.Start();
      34          }
      35          public void Start(Action action)
      36          {
      37              _action = action;
      38              if (_thread != null) throw new InvalidOperationException("任務已經開始");
      39              _thread = new Thread(() => Excute());
      40              _thread.Start();
      41          }
      42         public void Wait()
      43          {
      44              _thread.Join();
      45              if (_innerException != null) throw _innerException;
      46          }
      47      }
      48     public class MyTask<T> : MyTask
      49      {
      50          private Func<T> _func { get; }
      51          private T _result;
      52          public T Result {
      53              
      54              private set => _result = value;
      55              get 
      56              {
      57                  base.Wait();
      58                  return _result;
      59              }
      60          }
      61          public MyTask(Func<T> func)
      62          {
      63              _func = func;
      64          }
      65         public new void Start() 
      66          {
      67              base.Start(() =>
      68              {
      69                  Result = _func();
      70              });
      71          }
      72     }
      73 }
      View Code


            簡單的包裝了一下(不要在意細節),我們便可以實現我們想要的效果。

            測試代碼如下

       1 public static void ThrowException()
       2 {
       3      throw new Exception("發生異常");
       4 }
       5 public static void Test3()
       6 {
       7      MyTask<string> myTask = new MyTask<string>(() =>
       8      {
       9          Thread.Sleep(1000);
      10          return "執行完畢";
      11      });
      12     myTask.Start();
      13     try
      14      {
      15          Console.WriteLine(myTask.Result);
      16      }
      17      catch (Exception e)
      18      {
      19          Console.WriteLine(e.Message);
      20      }
      21 }
      22 public static void Test2()
      23 {
      24      MyTask<string> myTask = new MyTask<string>(() =>
      25      {
      26          Thread.Sleep(1000);
      27          ThrowException();
      28          return "執行完畢";
      29      });
      30     myTask.Start();
      31     try
      32      {
      33          Console.WriteLine(myTask.Result);
      34      }
      35      catch(Exception e)
      36      {
      37          Console.WriteLine(e.Message);
      38      }
      39 }
      40 public static void Test1()
      41 {
      42      MyTask myTask = new MyTask(() =>
      43      {
      44          Thread.Sleep(1000);
      45          ThrowException();
      46      });
      47      myTask.Start();
      48     try
      49      {
      50          myTask.Wait();
      51      }
      52      catch (Exception e)
      53      {
      54          Console.WriteLine(e.Message);
      55      }
      56 }
      57 static void Main(string[] args)
      58 {
      59      Test1();
      60      Test2();
      61      Test3();
      62 }


      image

            可以看到,我們可以通過簡單包裝Thread對象,便可實現如下效果

      • 直接讀取線程函數返回值
      • 直接捕捉線程函數未捕捉的異常(前提是調用了Wait()函數或者Result屬性)

            這是理解和運用Task的基礎,Task功能非常完善,但是運用好Task需要掌握許多概念,下面再說。

      下一篇:(二)線程池與TPL

      posted @ 2020-06-21 12:53  白煙染黑墨  閱讀(2643)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 免费看婬乱a欧美大片| 国产精品中文第一字幕| av亚洲一区二区在线| 亚洲欧美人成电影在线观看| 国产三级精品三级在线区| 亚洲国产成人一区二区在线| 日韩一区二区三区女优丝袜| 国产99青青成人A在线| 久99久热免费视频播放| 天天澡日日澡狠狠欧美老妇| 日韩国产精品中文字幕| 少妇无码av无码一区| 亚洲综合在线一区二区三区| 国产尤物精品自在拍视频首页| 国产不卡在线一区二区| 九九热视频在线免费观看| 欧美黑吊大战白妞| 亚洲一国产一区二区三区| 性xxxx欧美老妇胖老太性多毛| av色蜜桃一区二区三区| 国产999久久高清免费观看| 国产在线98福利播放视频| 婷婷国产成人精品视频| 99久久精品午夜一区二区| 亚洲欧洲日韩精品在线| 成人福利国产午夜AV免费不卡在线| 99精品国产一区二区三区| 一区二区丝袜美腿视频| 久久精品夜夜夜夜夜久久| 日韩一区二区三区精品区| 大陆精大陆国产国语精品| 亚洲精品蜜桃久久久久久| 精品久久人人妻人人做精品| 国产精品先锋资源站先锋影院| 国产成人8X人网站视频| jizzjizz少妇亚洲水多| 欧美日韩国产亚洲沙发| 中文无码人妻有码人妻中文字幕| 中文字幕日韩精品亚洲一区| 少妇被爽到高潮喷水久久欧美精品| 色吊丝一区二区中文字幕|