併發編程相關概念

来源:https://www.cnblogs.com/BigBrotherStone/archive/2020/01/28/12237571.html

" 返回《C 併發編程》" "1. 概念介紹" "2. 非同步編程" "2.1. async運行過程" "2.2. async運行中同步上下文簡介" "2.3. 創建Task實例" "2.4. 捕獲非同步異常類型" "3. 並行編程" "3.1. Parallel" "3.2. 異常處理" "3.3. ...


>>返回《C# 併發編程》

1. 概念介紹

現在我們先說明幾個概念:

  • 併發
    • 就是同時做多件事情,比如:
      • 程式寫入資料庫的同時響應用戶輸入
      • 伺服器處理第一個請求的同時響應第二個請求。
  • 多線程
    • 是併發的一種形式,它採用多個線程來執行程式,
      • 註意: 多線程是併發的一種形式,但並不是唯一的形式。
    • 多線程是比較基礎的技術,我們需要理解,知曉原理,但是真正使用時最好使用對多線程進行封裝的類,這樣能更好的節省資源,減少問題的產生。
  • 並行處理
    • 把正在執行的大量的任務分割成小塊,分配給多個同時運行的線程。
    • 這樣會使處理器的利用效率最大化,使用時需要註意因為控制不好的化會在短時間內極大的降低伺服器的處理性能
  • 非同步編程
    • 併發的一種形式,它採用未來模式(future)或回調機制(callback),以避免產生不必要的線程
      • 在 .NET 中,新版中使用 TaskTask<TResult>類型實現未來模式,在老式非同步編程 API 中,採用回調或事件(event)
    • 也是關鍵字 asyncawait 解決的問題
  • 響應式編程
    • 一種聲明式的編程模式,程式在該模式中對事件做出響應。

2. 非同步編程

2.1. async運行過程

  • async 方法在開始時以同步方式執行。在 async 方法內部,運行到await 關鍵字會執行一個非同步等待
    • 它首先檢查操作是否已經完成,如果完成了,就繼續運行 (同步方式)。
    • 否則,它會暫停 async 方法,並返回,留下一個未完成task
    • 一段時間後,await住的操作完成,async 方法就恢復運行(不一定是原來的線程,具體看同步上下文的配置)。

2.2. async運行中同步上下文簡介

  • 最常見的情況是,用 await 語句等待一個任務完成,這時會捕捉同步上下文。
    • 如果當前 SynchronizationContext 不為空,這個上下文就是當前 SynchronizationContext
    • 如果當前 SynchronizationContext 為空,則這個上下文為當前 TaskScheduler。
  • 該方法會在這個上下文中繼續運行。
    • 運行 UI 線程時採用 UI 上下文
    • 處理 ASP.NET 請求時採用 ASP.NET 請求上下文
    • 其他很多情況下則採用線程池上下文(上下文為 null 時)

註意: 最好的做法是,在核心庫代碼中一直使用 ConfigureAwait 。在外圍的用戶界面代碼中,只在需要時才恢覆上下文。

2.3. 創建Task實例

  • 兩種基本的方法可以創建 Task 實例。
    • 有些任務表示 CPU 需要實際執行的指令,創建這種計算類的任務時,使用 Task.Run
      • 如UI線程觸發的事件,如讀取目錄信息,配合 await 關鍵字,將任務交給線程池完成,解決讀取時窗體卡頓情況
    • 如需要按照特定的計劃運行,則用 TaskFactory.StartNew
    • 其他的任務表示一個通知( notification 操作會在回調中完成再通知回來),創建這種基於事件的任務時,使用 TaskCompletionSource<T>
      • 大部分 I/O 型任務採用 TaskCompletionSource<T>

2.4. 捕獲非同步異常類型

  1. 捕獲await拋出的異常,我們更想要
try
{
    await Task.Run(() => throw new NotSupportedException());
}
catch (Exception ex)
{
    //print: NotSupportedException
    Console.WriteLine(ex.GetType().Name);
}
  1. Wait()方法,異常類型被包裝
try
{
    Task task = Task.Run(() => throw new NotSupportedException());
    task.Wait();
}
catch (Exception ex)
{
    //print: AggregateException
    Console.WriteLine(ex.GetType().Name);
}

3. 並行編程

  • 並行編程可臨時提高 CPU 利用率,以提高吞吐量。
    • 若客戶端系統中的 CPU 經常處於空閑狀態,這個方法就非常有用
    • 通常並不適合伺服器系統,將降低本身的並行處理能力,並且不會有實際的好處。

反面教材: 之前在工作中出現一起事故,實施好的項目,3個月後每天凌晨出現大量設備掉線的情況。

  1. 由於數據超時時間時3個月,而且發現出現問題的日誌和數據清理髮生時間有關聯關係
  2. 排查代碼發現文件清理器,清理數據使用的Parallel類,並行刪除文件,而且沒有對併發數限制
  3. 文件清理器運行時,導致伺服器性能急劇下降,造成處理設備消息延遲,心跳超時導致掉線
  4. 重構了文件清理器代碼,解決了這個問題
  • 數據並行(data parallelism):
    • 是指有大量的數據需要處理,並且每一塊數據的處理過程基本上是彼此獨立的。
  • 任務並行(task parallelim):
    • 是指需要執行大量任務,並且每個任務的執行過程基本上是彼此獨立的。

3.1. Parallel

不保證順序執行。

//ForEach
int[] arr = new int[] { 1, 2, 3, 4 };
Parallel.ForEach(arr, item => Console.Write(item));
System.Console.WriteLine();

//PLINQ
var sum = arr.AsParallel().Select(item => item * 2).Sum();
System.Console.WriteLine($"sum:{sum}.");

//Invoke
int num = 10;
Parallel.Invoke(
    () => num += 2,
    () => num -= 2,
    () => num -= num,
    () => num += 2
);
System.Console.WriteLine($"num:{num}.");
/* 
print:
1243
sum:20.
num:0.
*/

3.2. 異常處理

系統會把這些異常封裝在 AggregateException 類里,在程式中拋給代碼。 這一特點對所有方法都是一樣的,包括 Parallel.ForEach、Paralle.lInvoke、Task.Wait 等。 AggregateException 類型有幾個實用的 Flatten 和 Handle 方法,用來簡化錯誤處理的代碼:

try 
{
    Parallel.Invoke(() => { throw new Exception(); },
    () => { throw new Exception(); });
}
catch (AggregateException ex)
{
    ex.Handle(exception =>
    {
        Console.WriteLine(exception);
        return true; //“已經處理” 
    });
}

3.3. 註意事項

在編寫任務並行程式時,要格外留意下閉包(closure)捕獲的變數。 記住閉包捕獲的是引用(不是值),因此可以在結束時以不明顯地方式地分享這些變數。

  • 任務不要特別短
    • 沒必要用,直接同步執行
  • 也不要特別長
    • 應採用更可控的方式,削峰設計

4. 響應式編程

如果事件中帶有參數,那麼最好 採用響應式編程,而不是常規的事件處理程式。

//System.Runtime.dll namespace:System 中定義了這些介面
interface IObserver<in T>
{
    void OnNext(T item);
    void OnCompleted();
    void OnError(Exception error);
}
interface IObservable<out T>
{
    IDisposable Subscribe(IObserver<T> observer);
}

Rx(Rx-Main)中定義了響應式編程的封裝,後面會有介紹。


您的分享是我們最大的動力!

更多相關文章
  • 反射這個詞聽起來就很牛逼是吧? 嗯的確,反射是比較高級的特性,只有語言基礎很扎實的Dev們才應該使用它。 搞點反射,可以提高程式的靈活性、可擴展性、耦合度。 反射這東西,是為了動態地運行時載入,相比於靜態代碼。編譯的時候就是板上釘釘了。 就是說,如果你的程式需要在運行時搞一些晚綁定,動態載入或檢查對 ...
  • 滑鼠事件執行幾個關聯的任務。當滑鼠移到某個元素上時,可通過最基本的滑鼠事件進行響應。這些事件是MouseEnter(當滑鼠指針移到元素上時引發該事件)和MouseLeave(當滑鼠指針離開元素時引發該事件)。這兩個事件都是直接事件,這意味著他們不使用冒泡和隧道過程,而是源自一個元素並且只被該元素引發 ...
  • static void LocalMethod() { Cube(100); void Cube(int x) => Console.WriteLine($"The cube of {x} is {x * x * x}"); } static void GoToDemo() { int i = 1; ...
  • 當用戶按下鍵盤上的一個鍵時,就會發生一系列事件。下表根據他們的發生順序列出了這些事件: 表 所有元素的鍵盤事件(按順序) 鍵盤處理永遠不會像上面看到的這麼簡單。一些控制項可能會掛起這些事件中的某些事件,從而可執行自己更特殊的鍵盤處理。最明顯的例子是TextBox控制項,它掛起了TextInput事件。對 ...
  • Linux下有vsyscall來優化一些例如time(NULL), gettimeofday這種調用的消耗; 但是Windows下, 沒有類似的東西, 但是思路還是有的 1. 程式啟動的時候, 獲取一下準確的時間戳 2. 然後每次需要獲取時間的時候, 獲取一下流逝的時間, 可以通過獲取CPU的tic ...
  • 創建一個bat腳本, 裡面寫上: reg delete HKEY_CURRENT_USER\Software\JetBrains\dotMemory /freg delete HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Ex ...
  • 原來的導出方式比較適用於比較簡單的導出,每一條數據在一行,數據列雖然自定義程度比較高,如果要一條數據對應多行就做不到了,於是就想支持根據模板導出,在 1.8.0 版本中引入了根據模板導出的功能 ...
  • 我們先看看兩個特效,感受一下,有沒有學習的動力? 核心API:Texture2D.SetPixel(int x, int y, Color color),Texture2D.Apply() 實現原理:對象池 思路: 第一幀繪製前:遍歷瓦片上所有活著的粒子對象並且進行數據操作(或運動,死亡),發生運動 ...
一周排行
  • 本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/8135083.html,記錄一下學習過程以備後續查用。 一、引言 今天我們要講行為型設計模式的第九個模式--訪問者模式。如果按老規矩,先從名稱上來看這個模式,我根本不能獲得任何對理解該模式有用的信息, 而且這個 ...
  • 微信公眾號:【 "Dotnet9的博客" 】,網站:【 "Dotnet9" 】,問題或建議:【 "請網站留言" 】, 如果對您有所幫助:【 "歡迎贊賞" 】。 開源C WPF控制項庫系列: "(一)開源C WPF控制項庫《MaterialDesignInXAML》" "(二)開源C WPF控制項庫《Pan ...
  • 如今,當談到 WPF 時,我們言必稱 MVVM、框架(如 Prism)等,似乎已經忘了不用這些的話該怎麼使用 WPF 了。當然,這裡說的不用框架和 MVVM,並不是說像使用 Winform 那樣使用 WPF,而是追本溯源,重識 WPF 與生俱來的綁定和命令的風采。 ...
  • 本筆記摘抄自:https://www.cnblogs.com/PatrickLiu/p/8176974.html,記錄一下學習過程以備後續查用。 一、引言 今天我們要講行為型設計模式的第十個模式--備忘錄模式,先從名稱上來看。備忘錄模式可以理解為對某個對象的狀態進行保存,等到需要恢復的時 候,可以從 ...
  • 前言 在兩年多以前就聽聞 Blazor 框架,是 .Net 之父的業餘實驗性項目,其目的是探索 .Net 與 WebAssembly 的相容性和應用前景。現在這個項目已經正式成為 Asp.Net Core 框架的一部分,公開了預覽版,官方教程也基本寫好上線了。就著這個機會,順便體驗一下這個框架用起來 ...
  • .NET web開發者在開發過程中,一定都踩過的坑,明明修改了js文件,可是部署到生產環境,客戶反饋說:“還是報錯啊”。。然後一臉懵逼的去伺服器上看文件,確實已經更新了。有經驗的coder可能就想到了,肯定是客戶端瀏覽器緩存搞的鬼。 此時會告訴客戶,請Crtl+F5刷新一下,這時,客戶會說:“Ctr ...
  • 哈嘍..大家好 很久沒有更新了,今天就來一篇最近開發用到的功能,那就是中英文切換,這個實際上也不是高大上,先說一下原理,在.NET Core框架中給我們提供了全球化的類,叫做Localization,其官方的文檔地址傳送門。 在我的項目中,我是這樣操作的,你想用別的方式,也可以看文檔自己去搞。這個已 ...
  • WPF允許使用Image元素顯示點陣圖。然而,按這種方法顯示圖片的方法完全是單向的。應用程式使用現成的點陣圖,讀取問題,併在視窗中顯示點陣圖。就其本身而言,Image元素沒有提供創建和編輯點陣圖信息的方法。 這正是WriteableBitmap類的用武之地。該類繼承自BitmapSource,BitmapS ...
  • 記錄LINQ學習過程。 概要 LINQ是一種“語言集成”的查詢表達式,使用LINQ可以智能提示和進行類型檢查。C#里可以編寫的LINQ查詢有SQL資料庫、XML文檔、ADO.NET數據集、支持IEnumerable和IEnumerable的對象。使用LINQ,可以簡單對數據源進行分組、排序、篩選。有 ...
  • 這兩天複習了下Request以及Response部分的內容。 主要內容 1. HTTP協議:響應消息 2. Request對象 3. Response對象 4. ServletContext對象 HTTP: 概念:Hyper Text Transfer Protocol 超文本傳輸協議 傳輸協議:定 ...
x