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

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

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

      Csharp線程

      CSharpe線程

      什么是進程?

      一個應用程序的運行---對標于一個進程----虛擬詞;
      所謂的進程---記錄了程序運行所消耗的各種各樣的資源;

      什么是線程?

      就是計算機程序在運行的時候,執行指令的最小的執行流~ 程序
      的運行---很多的并發操作,任何一個指令的執行都是需要通過線程來完成;
      一個進程至少要包含一個線程;進程退出,線程也是自動消失;

      什么是多線程?

      隨著技術的發展---業務的需求---需要指令的并發執行;
      同時執行多種指令(線程來執行的);
      和CPU的核數有關~~

      C#如何操作線程

      1. Thread(很少用)
      2. ThreadPool(線程池)
      3. Task(主流-----重點)

      Thread

      Thread:來自于System.Threading的一個密封類,它是在.net Framwork1.0時代出現的,在C#中用來操作計算機資源線程的一個幫助類庫;

      1. Thread如何開啟一個線程呢?

      多線程因為是無序的,調試不太好調試,只能通過寫日志,輸出結果,根據結果來判斷thread的特點.

      private void btn_Thread_Click(object sender, EventArgs e)
      {
          Debug.WriteLine($"***************Main Thread start: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
      
          Thread thread = new Thread(() =>
          {
              Debug.WriteLine($"***************Thread start: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
             
              Debug.WriteLine($"***************Thread end: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
          });
      
          thread.Start();
      
          Debug.WriteLine($"***************Main Thread end: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
      }
      

      結果

      img

      2. Thread中常見的API

      thread.Suspend(); // 線程暫停
      thread.Resume();  // 線程恢復
      thread.Abort();   // 線程終止
      
      1.線程等待的:ThreadState有多種狀態;如果線程停止了,狀態會修改;
      
      while (thread.ThreadState != System.Threading.ThreadState.Stopped) //如果線程沒有停止;
      {
          Thread.Sleep(500); //當前休息500ms  不消耗計算機資源的
      }
      
      2.自己支持的線程等待: 
      thread.Join();//等待線程中的內容執行完畢;繼續往后; 
      thread.Join(500);//等待500ms,過時不候;
      thread.Join(TimeSpan.FromMilliseconds(500));//等待500ms,過時不候;
      
      
      thread.IsBackground = true;// 是后臺線程:程序強制關掉,線程也就隨之消失了; 
      thread.IsBackground = false; //是前臺線程:程序強制關掉,線程會等待,內部的行為執行完畢,然后才結束;
      thread.Start(); 
      
      

      3. thread的擴展封裝

      多線程;異步執行;
      不阻塞界面;
      無序性---多個動作。如果使用多線程,是無法控制順序的。

      現在有兩個動作 使用了2個委托 必須是多線程執行的 要求兩個委托按順序執行。

       Action action = () => { Debug.WriteLine("this is first run"); };
      
       Action action2 = () => { Debug.WriteLine("this is second run"); };
      
       private void button1_Click(object sender, EventArgs e)
       {
           callBack(action, action2);
       }
      
       private void callBack(Action action,Action action1)
       {
          Thread t= new Thread(() =>
          {
              action();
              action1();
          });
           t.Start();
       }
      

      如果有一個帶返回值的委托,需要你要多線程執行;

       Func<int> func = () => { return DateTime.Now.Year; };
      
       private void button1_Click(object sender, EventArgs e)
       {
           Func<int> func1= CallBack<int>(func);
           Debug.WriteLine("t****************");
           Debug.WriteLine("t****************");
           Debug.WriteLine("t****************");
           Debug.WriteLine("t****************");
           Debug.WriteLine("t****************");
           Debug.WriteLine("t****************");
           int iResult=func1();
           Debug.WriteLine(iResult);
      
       }    
       private Func<T> CallBack<T>(Func<T> func)
       {
           T result = default(T);
           Thread t = new Thread(() =>
           {
               result = func();
           });
           t.Start();
      
           return new Func<T>(() => { 
               t.Join();
               return result; });
          
       }
      

      threadpool

      Thread對比Threadpool:Api很多,功能繁多;使用起來,不好控制;讓開發者試用起來并不友好;
      Thread對線程的數量管控,全部都需要讓程序員自己來管控;

      一、 .NET Framework2.0時代:出現了一個線程池ThreadPool

      是一種池化思想,相當于是在池子中,有線程存在;如果需要使用線程;就可以直接到線程池中去獲取直接使用,如果使用完畢,在自動的回放到線程池中去;

      好處:
      1.不需要程序員對線程的數量管控,提高性能,放置濫用
      2.去掉了很多在Thread中沒有必要的Api

      二、線程池如何申請一個線程呢?

       ThreadPool.QueueUserWorkItem((state) =>
       {
           Debug.WriteLine($"***************ThreadPool start: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
           Thread.Sleep(5000);
           Debug.WriteLine($"***************ThreadPool end: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
       });
      

      三、線程等待

      1. 觀望式的:
      2. 定義一個監聽ManualResetEvent
      3. 通過ManualResetEvent.WaitOne等待
      4. 等到ManualResetEvent.Set方法執行,方法執行完畢后,主線程就繼續往后;
                  ManualResetEvent manualResetEvent = new ManualResetEvent(false);
                  ThreadPool.QueueUserWorkItem((state) =>
                  {
                      Debug.WriteLine($"***************ThreadPool start: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
                      Thread.Sleep(5000);
                      Debug.WriteLine($"***************ThreadPool end: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
                      manualResetEvent.Set();
                  });
                  manualResetEvent.WaitOne();
                  Debug.WriteLine($"***************Main Thread end: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
              }
      

      四、線程池如何控制線程數量

      如果通過SetMinThreads/SetMaxThreads來設置線程的數量;這個數量訪問是在當前進程是全局的;

       {
           int workerThreads = 4;
           int completionPortThreads = 4;
           ThreadPool.SetMinThreads(workerThreads, completionPortThreads);
       }
       {
           int workerThreads = 8;
           int completionPortThreads = 8;
           ThreadPool.SetMaxThreads(workerThreads, completionPortThreads);
       }
       {
           ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
           Debug.WriteLine($"當前進程最小的工作線程數量:{workerThreads}");
           Debug.WriteLine($"當前進程最小的IO線程數量:{completionPortThreads}");
       }
       {
           ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
           Debug.WriteLine($"當前進程最大的工作線程數量:{workerThreads}");
           Debug.WriteLine($"當前進程最大的IO線程數量:{completionPortThreads}");
       } 
      

      Task

      一、Task開啟線程有哪些方式

      Action action = () =>
      {
          Console.WriteLine($"***************Task start: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
          Console.WriteLine("啟動了一個新的線程");
          Console.WriteLine($"***************Task end: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
      };
      
      Task task = new Task(action);
      task.Start();
      
      Task.Run (() =>
      {
          Console.WriteLine($"***************Task.Run start: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
          Console.WriteLine("啟動了一個新的線程");
          Console.WriteLine($"***************Task.Run end: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
      });
      
      
      TaskFactory taskFactory = new TaskFactory();
      taskFactory.StartNew(() =>
      {
          Console.WriteLine($"***************TaskFactory start: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
          Console.WriteLine("啟動了一個新的線程");
          Console.WriteLine($"***************TaskFactory end: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
      });
      
      Task.Factory.StartNew(() =>
      {
          Console.WriteLine($"***************Task.Factory start: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
          Console.WriteLine("啟動了一個新的線程");
          Console.WriteLine($"***************Task.Factory end: {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("HH:mm:ss.fff")} **************** ");
      });
      
      

      啟動的多線程的特點:

      1. 不阻塞主線程----不會卡頓界面
      2. 線程的啟動---由操作系統來調度啟動; 延遲啟動(延遲很短)
      3. 并發執行~~

      線程執行完畢就銷毀了嗎?
      ThreadPool 線程池----Task 線程都是來自于線程池的;

      多進程技術的使用場景的分析

      問題:盡可能的多啟動線程?? 萬萬不可的,一定要適當的使用;
      一堆業務邏輯: 項目要開發 10個板塊
      單線程執行: 一個人去承擔這個項目開發----一步一步的做;一個版快一個板塊的去開發; 開發周期時間長
      多線程執行: 一個團隊開發: 效率更高~~ 多個人可以分工開發;
      類比: 一個人(開支小)和一個團隊(10個人 10份工資);

      線程等待

      有Delay 和 Sleep兩種方式來進行線程的等待.

      {
          Stopwatch stopwatch = new Stopwatch();
          stopwatch.Start();
          Task.Delay(3000);
          stopwatch.Stop();
          Console.WriteLine($"time:{stopwatch.ElapsedMilliseconds}");
      }
      
      
      {
          Stopwatch stopwatch = new Stopwatch();
          stopwatch.Start();
          Thread.Sleep(3000);
          stopwatch.Stop();
          Console.WriteLine($"time:{stopwatch.ElapsedMilliseconds}");
      }
      

      結果為:

      img

      Task.Delay().ContinueWith() 不阻塞主線程,等待多長時間之后,可以執行一段業務邏輯----回調函數
      Thread.Sleep() 阻塞主線程,主線程等待指定時間后再運行。

      線程等待的多種方案

        Task<int> task = Task.Run(() =>
        {
            Thread.Sleep(3000);
      
            Console.WriteLine("Open new thread!");
      
            return 10;
        });
      
        int num = task.Result; //等待task執行完畢,獲取返回值,會阻塞當前線程
      
         //下面是沒有返回值方法調用的時候,使用的方法
           //Task.WaitAll(task); //等待task執行完畢,會阻塞當前線程
      
          //int i = Task.WaitAny(task); //等待task執行完畢,會阻塞當前線程
      

      什么場景下可以使用多線程呢?(可以并發的時候) 不適合使用多線程??
      故事: 高級班的項目實戰---逐個講解知識點,然后項目實戰,分工合作,分小組開發;

      1. 逐個講解知識點 -----可以多線程來模擬?---只有Richard老師一個人講解----不可用;不能并發,不能多線程來模擬
      2. 項目實戰,分工合作,分小組開發; -----可以多線程來模擬?---有多個人同時開發,可以分工并發開發,可以多線程開發~~

      模擬的代碼

       /// <summary>
       /// 模擬講課的方法
       /// </summary>
       /// <param name="lesson">課程名</param>
       private void Tech(string lesson)
       {
           Console.WriteLine($"{lesson} ||開始了.....");
           long iResult = 0;
      
           for (int i = 0;i<1_000_000_000;i++)
           {
               iResult += i;
           }
           Console.WriteLine($"{lesson} ||講完了.....");
       }
       /// <summary>
       /// 模擬不同人開發的方法
       /// </summary>
       /// <param name="name"></param>
       /// <param name="projectName"></param>
       private void Coding(string name,string projectName)
       {
           Console.WriteLine($"************************* Coding Start || {name}  {projectName} {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} ****************");
           long iResult = 0;
      
           for (int i = 0; i < 1_000_000_000; i++)
           {
               iResult += i;
           }
           Console.WriteLine($"************************* Coding End || {name}  {projectName} {Thread.CurrentThread.ManagedThreadId.ToString("00")}  {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} ****************");
       }
      

      基礎的項目流程

      private void button5_Click(object sender, EventArgs e)
      {
          Console.WriteLine("同學們!開始上課了");
          Tech("泛型");
          Tech("委托");
          Tech("多線程");
          Tech("異步編程");
          Tech("并發編程");
          Console.WriteLine("知識點講解完畢了~~開始項目實戰開發`~~~");
          TaskFactory factory = new TaskFactory();
      
          factory.StartNew(() => Coding("張三", "數據庫設計"));
          factory.StartNew(() => Coding("李四", "框架的搭建"));
          factory.StartNew(() => Coding("王五", "Wechat Pay"));
          factory.StartNew(() => Coding("趙六", "Web Api"));
          factory.StartNew(() => Coding("田七", "封裝通用的組件"));                
          factory.StartNew(() => Coding("劉八", "編譯"));
          factory.StartNew(() => Coding("楊九", "發行"));
      
          
      }
      

      需求一、所有人的任務都執行完成后,小聚一下,大吃一頓```

        private void button5_Click(object sender, EventArgs e)
        {
      
            List<Task> tasks = new List<Task>();
            Console.WriteLine("同學們!開始上課了");
            Tech("泛型");
            Tech("委托");
            Tech("多線程");
            Tech("異步編程");
            Tech("并發編程");
            Console.WriteLine("知識點講解完畢了~~開始項目實戰開發`~~~");
            TaskFactory factory = new TaskFactory();
      
            tasks.Add( factory.StartNew(() => Coding("張三", "數據庫設計")));
            tasks.Add(factory.StartNew(() => Coding("李四", "框架的搭建")));
            tasks.Add(factory.StartNew(() => Coding("王五", "Wechat Pay")));
            tasks.Add(factory.StartNew(() => Coding("趙六", "Web Api")));
            tasks.Add(factory.StartNew(() => Coding("田七", "封裝通用的組件")));
            tasks.Add(factory.StartNew(() => Coding("劉八", "編譯")));
            tasks.Add(factory.StartNew(() => Coding("楊九", "發行")));
      
            Task.WaitAll(tasks.ToArray());
            Console.WriteLine("項目開發完畢了~~~,去大吃一頓~~");      
        }
      

      需求2、 開發人員中,只要其中有一個執行完成了,Richard老師就準備發布環境,準備發布部署

       private void button5_Click(object sender, EventArgs e)
       {
      
           List<Task> tasks = new List<Task>();
           Console.WriteLine("同學們!開始上課了");
           Tech("泛型");
           Tech("委托");
           Tech("多線程");
           Tech("異步編程");
           Tech("并發編程");
           Console.WriteLine("知識點講解完畢了~~開始項目實戰開發`~~~");
           TaskFactory factory = new TaskFactory();
      
           tasks.Add( factory.StartNew(() => Coding("張三", "數據庫設計")));
           tasks.Add(factory.StartNew(() => Coding("李四", "框架的搭建")));
           tasks.Add(factory.StartNew(() => Coding("王五", "Wechat Pay")));
           tasks.Add(factory.StartNew(() => Coding("趙六", "Web Api")));
           tasks.Add(factory.StartNew(() => Coding("田七", "封裝通用的組件")));
           tasks.Add(factory.StartNew(() => Coding("劉八", "編譯")));
           tasks.Add(factory.StartNew(() => Coding("楊九", "發行")));
           {
               Task.WaitAny(tasks.ToArray());  //等待一堆任務中,其中有一個執行完成了,繼續往后執行~
               Console.WriteLine("XXX 完成了開發任務~~,Richard老師就準備發布環境,準備發布部署");
           }
           {
               Task.WaitAll(tasks.ToArray());
               Console.WriteLine("項目開發完畢了~~~,去大吃一頓~~");
           }
           
       }
      

      使用場景:
      Task.WaitAll----系統首頁---包含了很多的信息---都是后臺提供----獲取這個結果的時候;準備一個復雜實體---包含各種信息 查詢這些數據---可以多線程去執行;同時查詢;
      查詢必須要獲取到所有的數據----要獲取所有的數據----Task.WaitAll

      Task.WaitAny----查詢一條數據----數據來源可能是不同的地方,數據庫/緩存/接口/讀取硬盤中的數據
      1.傳統做法: 先查詢緩存試試看,如果沒有,再查詢數據庫,如果沒有,再繼續往后,直到查詢到數據為止;
      2.有四個渠道獲取數據----> 只要有一個渠道獲取到數據就Ok, 直接啟動四個線程去查詢; 等待其中有一個線程執行完成,特殊處理,如果查詢到數據后,就結束~~ 只要有一個執行結束了,就已經拿到數據了,其他的不用管了~~

      需求3、 有沒有可以不阻塞主線程,也能達到效果;

       private void button2_Click(object sender, EventArgs e)
       {
           List<Task> tasks = new List<Task>();
           Console.WriteLine("同學們!開始上課了");
           Tech("泛型");
           Tech("委托");
           Tech("多線程");
           Tech("異步編程");
           Tech("并發編程");
           Console.WriteLine("知識點講解完畢了~~開始項目實戰開發`~~~");
           TaskFactory factory = new TaskFactory();
      
           tasks.Add(factory.StartNew(Object => Coding("張三", "數據庫設計"),"張三"));
           tasks.Add(factory.StartNew(Object => Coding("李四", "框架的搭建"), "李四"));
           tasks.Add(factory.StartNew(Object => Coding("王五", "Wechat Pay"), "王五"));
           tasks.Add(factory.StartNew(Object => Coding("趙六", "Web Api"), "趙六"));
           tasks.Add(factory.StartNew(Object => Coding("田七", "封裝通用的組件"), "田七"));
           tasks.Add(factory.StartNew(Object => Coding("劉八", "編譯"), "劉八"));
           tasks.Add(factory.StartNew(Object => Coding("楊九", "發行"), "楊九"));
         
      
           {
               factory.ContinueWhenAny(tasks.ToArray(), (task) =>
               {
                   Console.WriteLine($"{task.AsyncState} 完成了開發任務~~,發一個小紅包");
               });
           }
           {
               factory.ContinueWhenAll(tasks.ToArray(), (task) =>
               {
                   Console.WriteLine("項目開發完畢了~~~,去大吃一頓~~");
               });
               
           }
       }
      

      需求4、如果想要完成以上需求,要求不阻塞主線程,如果也沒有ContinueWhenAll api.

      
      Task.Run(() =>
      {
          Task.WaitAll(tasks.ToArray());
          Console.WriteLine("項目開發完畢了~~~,去大吃一頓~~");
      });
      

      通過Task返回一個字符串

      {
          List<Task<string>> tasklist = new List<Task<string>>();
          for (int i = 0; i < 3; i++)
          {
              string k = $"{i}";
              tasklist.Add(Task.Run(() =>
              {
                  return $"{k}_Task";
              }));
          }
          Task.Run(() =>
          {
              Task.WaitAny(tasklist.ToArray());
              Task<string> task = tasklist.First(c => c.Status == TaskStatus.RanToCompletion);
              Console.WriteLine(task.Result);
          });
      }
      

      Paralell

      如何批量開啟10個線程?

       Parallel.For(0, 10, (i) =>
       {
        
      
       Console.WriteLine($"Thread id : {Thread.CurrentThread.ManagedThreadId.ToString("00")  }") ;
      
       });
      

      如何控制啟動線程的數量?

       ParallelOptions parallelOptions = new ParallelOptions();
       parallelOptions.MaxDegreeOfParallelism = 10;
      
       Parallel.For(0, 10100, parallelOptions, (i) =>
       {
           Console.WriteLine($"Thread id : {Thread.CurrentThread.ManagedThreadId.ToString("00")  }");
      
       });
      

      線程異常處理

      1.try_catch捕獲不到多線程內部的異常.

      按照正常的Try Catch來處理異常。

      try {
          for (int i = 0; i < 20; i++)
          {
              string str = $"Advance_{i}";
              Task.Run(() =>
              {
                  if (str.Equals("Advance_7"))
                  {
                      throw new Exception("Advance_7異常");
                  }
                  else if (str.Equals("Advance_10"))
                  {
                      throw new Exception("Advance_{10}異常");
                  }
                  else if (str.Equals("Advance_15"))
                  {
                      throw new Exception("Advance_15異常");
                  }
                  else if (str.Equals("Advance_18"))
                  {
                      throw new Exception("Advance_18異常");
                  }
                  else
                  {
                      Console.WriteLine(str);
                  }
              });
      
      
          }
      } 
      catch (Exception ex) 
      { 
          Console.WriteLine(ex.Message); 
      }
      

      2.如何捕捉線程內部的異常,try-catch 包裹,線程等待; 可以捕捉到AggregateException類型的異常;
      3.一個try可以對應多個catch 發生異常后,catch捕捉,是從上往下匹配異常類型,只要是匹配到異常類型后,就進入開始處理異常;
      4.如何輸出消息, 要轉換成AggregateException,獲取InnerExceptions 的集合,多線程發生的多個異常,都在這個集合中;

        private void button4_Click(object sender, EventArgs e)
        {
      
            List<Task> tasks = new List<Task>();
            try {
                for (int i = 0; i < 20; i++)
                {
                    string str = $"Advance_{i}";
                    Task task = Task.Run(() =>
                    {
                        if (str.Equals("Advance_7"))
                        {
                            throw new Exception("Advance_7異常");
                        }
                        else if (str.Equals("Advance_10"))
                        {
                            throw new Exception("Advance_{10}異常");
                        }
                        else if (str.Equals("Advance_15"))
                        {
                            throw new Exception("Advance_15異常");
                        }
                        else if (str.Equals("Advance_18"))
                        {
                            throw new Exception("Advance_18異常");
                        }
                        else
                        {
                            Console.WriteLine(str);
                        }
                    });
                    tasks.Add(task);
                }
                Task.WaitAll(tasks.ToArray());
            } 
            catch (Exception ex) 
            { 
                Console.WriteLine(ex.Message); 
            }
            
        }
      

      線程取消

      有一個需求:
      首頁---數據塊---考情/周top10/月top ......
      啟動四個線程去獲取數據,要正常展示----一定要四個線程都能正常獲取到數據,必然要等待四個線程都執行結束;
      場景:四個線程,有某一個線程異常了~~ 整塊數據不能用; 如果有異常,其他的正常的線程,其實查詢也沒有價值,既然沒有異常的線程執行也沒價值,就應該取消-----(因為線程在執行業務邏輯---需要消耗計算機的資源,計算機的資源是有限的)

      標準方案:

      定義一個cts,包含一個IsCancellationRequested 屬性,默認值為=false,同時提供了一個Cancel方法, IsCancellationRequested: 默認的false ----true; IsCancellationRequested 屬性 只能通過Cancel來變化,不能通過其他的渠道修改;

       CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
       
       
       try {
           for (int i = 0; i < 50; i++)
           {
               string str = $"Advance_{i}";
               Task.Run(() =>
               {
                   if (cancellationTokenSource.IsCancellationRequested == false)
                   {
                       Console.WriteLine("正常運行");
      
                       if (str.Equals("Advance_7"))
                       {
                           cancellationTokenSource.Cancel();
                           throw new Exception("Advance_7異常");
                       }
                       else if (str.Equals("Advance_10"))
                       {
                           cancellationTokenSource.Cancel();
                           throw new Exception("Advance_{10}異常");
                       }
                       else if (str.Equals("Advance_15"))
                       {
                           cancellationTokenSource.Cancel();
                           throw new Exception("Advance_15異常");
                       }
                       else if (str.Equals("Advance_18"))
                       {
                           cancellationTokenSource.Cancel();
                           throw new Exception("Advance_18異常");
                       }
      
                   }
                   else
                   {
                       Console.WriteLine("線程非正常退出");
                   }
               });
               
           }
           
       } 
       catch (Exception ex) 
       { 
           Console.WriteLine(ex.Message); 
       }
      

      多線程的中間變量

      先看一段代碼

      for (int i = 0; i < 10000; i++)
      {
          Task.Run(() => Console.WriteLine($"{i}"));
      }
      

      輸出的都是10000

      為什么會這樣那:
      int i = 0; 開始循環,定義好的一個變量;
      線程是延遲啟動,啟動線程不阻塞UI線程; 多線程要執行邏輯,要使用i,i已經是20了;

      要實現我們的目的

       for (int i = 0; i < 10000; i++)
       {
           int k = i;
      
           Task.Run(() => Console.WriteLine($"{k}"));
       }
      

      線程安全

      線程不安全:多線程在執行業務邏輯的時候,得到的結果,如果和單線程執行的結果如果不一致,那就是線程不安全~~
      線程安全:單線程執行的結果要和多線程執行的結果要一致;線程安全的;

      有多線程不安全的代碼

        private void button6_Click(object sender, EventArgs e)
        {
            List<int> list = new List<int>();
            List<Task> tasks = new List<Task>();
            for (int i = 0; i < 10000; i++)
            {
                tasks.Add(Task.Run(() => { list.Add(i); }));
            }
      
            Task.WaitAll(tasks.ToArray());
            Console.WriteLine(list.Count);
        }
      

      如何解決線程安全呢?

      1. 鎖, ----控制執行的線程只能有一個
      2. 直接使用單線程;
      3. 使用線程安全對象 看看數據結構 線程安全對象 List/Arraylist 都不是線程安全的集合--把list Arraylist 換成安全對象;
      4. 通過算法+拆分做到---劃塊操作數據; 原理:還是單線程去操作一塊數據;
       private readonly static object obj = new object();
       private void button6_Click(object sender, EventArgs e)
       {
           List<int> list = new List<int>();
           List<Task> tasks = new List<Task>();
           for (int i = 0; i < 10000; i++)
           {
      
               tasks.Add(Task.Run(() =>
               {
                   //鎖: 控制鎖內部的代碼執行,只能有一個線程進入執行,必須要等進入鎖的線程執行結束了,其他的線程才能再進去一個; 反多線程;
                   lock (obj)
                   {
                       list.Add(i);
                   }
               }));
      
      
           }
      
           Task.WaitAll(tasks.ToArray());
           Console.WriteLine(list.Count);
       }
      
      posted @ 2024-04-02 17:23  飄雨的河  閱讀(894)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 吕梁市| 免费AV片在线观看网址| 高清无码18| 动漫AV纯肉无码AV电影网| 精品国产AV无码一区二区三区| 中文字幕av日韩有码| 人妻丰满熟妇无码区免费| 亚洲色av天天天天天天| 久久免费观看归女高潮特黄| 亚洲精品乱码久久久久久蜜桃不卡| 久久久久久综合网天天| 国产盗摄视频一区二区三区| 国内精品免费久久久久电影院97| 国产成人精品无人区一区| 免费无码AV一区二区波多野结衣| 中文无码热在线视频| 午夜免费国产体验区免费的| 蓬安县| 国产亚洲亚洲国产一二区| 国产不卡一区二区在线| 国产中年熟女高潮大集合| 日韩一区二区三区在线观院| 国产美女被遭强高潮免费一视频| 人人玩人人添人人澡超碰| 久久香蕉欧美精品| 国产成人精品永久免费视频| 国产超碰无码最新上传| 囯产精品久久久久久久久久妞妞| 亚洲偷偷自拍码高清视频| 国产一区二区三区韩国| 亚洲av成人无码天堂| 欧美成人精品三级网站| 久久人妻无码一区二区| 青青草无码免费一二三区| 久久人妻夜夜做天天爽| 亚洲AVAV天堂AV在线网阿V | 亚洲三区在线观看无套内射| 丰满人妻熟妇乱又仑精品| 肉大捧一进一出免费视频| 中国china体内裑精亚洲日本| 亚洲精品国产第一区二区|