# C# 中的Task建立指南

本文還處於草稿階段,不免還有錯誤修改改正,邏輯還不是很清晰,筆者會努力完善,長期更新!html

[0000] 前言

標題起得有些"大",意在集你們的力量,總結出來一份關於Task相對"正確"的知識總結,歡迎讀者提出寶貴意見!本文內容來自於筆者在編碼的時候種種疑問,來自於對異步編程在操做系統中實際運行過程的好奇。平時使用Task戰戰兢兢,既想提升效率,又怕它不受控制,處處亂來。與其這樣,不如此時此刻一塊兒來了解它神祕的面紗吧!Just do IT.git

[0001] 爲何要編寫異步代碼

新型應用普遍使用文件和網絡 I/O。 默認狀況下 I/O API 通常會阻塞,致使糟糕的用戶體驗和硬件利用率,除非但願學習和使用富有挑戰的模式。 基於任務的異步 API 和語言級異步編程模型改變了這種模型,只需瞭解幾個新概念就可默認進行異步執行。github

異步代碼具備如下特色:編程

  • 等待 I/O 請求返回的同時,可經過生成處理更多請求的線程,處理更多的服務器請求。
  • 等待 I/O 請求的同時生成 UI 交互線程,並經過將長時間運行的工做轉換到其餘 CPU 核心,讓 UI 的響應速度更快。
  • 許多較新的 .NET APIs 都是異步的。
  • 在 .NET 中編寫異步代碼很簡單!

來源: https://docs.microsoft.comc#

[0010] 關於C#中的異步編程模式

.NET 提供了執行異步操做的三種模式:服務器

  • 基於任務的異步模式 (TAP) ,該模式使用單一方法表示異步操做的開始和完成。 TAP 是在 .NET Framework 4 中引入的。 這是在 .NET 中進行異步編程的推薦方法。 C# 中的 async 和 await 關鍵詞以及 Visual Basic 中的 Async 和 Await 運算符爲 TAP 添加了語言支持。 有關詳細信息,請參閱基於任務的異步模式 (TAP)網絡

  • 基於事件的異步模式 (EAP) ,是提供異步行爲的基於事件的舊模型。 這種模式須要後綴爲 Async 的方法,以及一個或多個事件、事件處理程序委託類型和 EventArg 派生類型。 EAP 是在 .NET Framework 2.0 中引入的。 建議新開發中再也不使用這種模式。 有關詳細信息,請參閱基於事件的異步模式 (EAP)多線程

  • 異步編程模型 (APM) 模式(也稱爲 IAsyncResult 模式),這是使用 IAsyncResult 接口提供異步行爲的舊模型。 在這種模式下,同步操做須要 BeginEnd 方法(例如,BeginWriteEndWrite以實現異步寫入操做)。 不建議新的開發使用此模式。 有關詳細信息,請參閱異步編程模型 (APM)異步

模式的比較

爲了快速比較這三種模式的異步操做方式,請考慮使用從指定偏移量處起將指定量數據讀取到提供的緩衝區中的Read方法:async

public class MyClass  
{  
    public int Read(byte [] buffer, int offset, int count);  
}

此方法對應的 TAP 將公開如下單個 ReadAsync 方法:

public class MyClass  
{  
    public Task<int> ReadAsync(byte [] buffer, int offset, int count);  
}

對應的 EAP 將公開如下類型和成員的集:

public class MyClass  
{  
    public void ReadAsync(byte [] buffer, int offset, int count);  
    public event ReadCompletedEventHandler ReadCompleted;  
}

對應的 APM 將公開 BeginReadEndRead 方法:

public class MyClass  
{  
    public IAsyncResult BeginRead(  
        byte [] buffer, int offset, int count,   
        AsyncCallback callback, object state);  
    public int EndRead(IAsyncResult asyncResult);  
}

來源: https://docs.microsoft.com

分割線,未完區域--------------------------------

[0011] 實踐

使用Async

請一路Async,不然會不可控。
網絡請求,文件讀寫時系統自帶的Async方法不會建立多線程,而是使用完成端口,依靠中斷來實現!
線程池中的線程分爲 WorkerThread 和 CompletionPortThread .
平時咱們使用的線程是WorkerThread,IO讀寫使用的是CompletionPortThread

1. 建立IO密集型任務

如下代碼不會建立多個線程(WorkerThread),代碼會在當前線程工做,且不會堵塞哦。
執行起來很是相似同步程序, 使用 await RunActionAsync(()=>{});
後,會當即執行程序

public Task RunActionAsync(Action action)
{
    TaskCompletionSource<Task> source = new TaskCompletionSource<Task>(TaskCreationOptions.AttachedToParent);
    Task<Task> task = source.Task;

    try
    {
        action.Invoke();
    }
    catch (Exception ex)
    {
        source.SetException(ex);
    }

    source.SetResult(Task.CompletedTask);

    return task;
}

2. 計算密集型任務

如下代碼會建立新線程(WorkerThread),位於線程池,線程池默認最小WorkerThread爲CPU核心數,CompletionPortThread爲1000(實際最小值依實際運行狀況而定,可手工修改)
運行時並不會當即執行Action,按照默認執行計劃(TaskScheduler.Default執行,好比用for循環一堆Task.Run(async ()=> {await httpgetAsync(); echo(i); )任務,執行時你會發現i都是最後一個值

await Task.Run(()=>{});

如下代碼會建立新線程(WorkerThread),在不在ThreadPool關鍵在於TaskCreationOptions枚舉,若是爲LongRunning,則直接會建立一個非線程池的線程執行任務,若是不是,則會在線程池裏尋找線程,若是沒有,會在線程池裏新申請線程(建立一個耗時一秒),執行任務。
會當即執行Action

Task.Factory.StartNew(_ =>
{
    action.Invoke();
},
    null,
    CancellationToken.None,
    TaskCreationOptions.LongRunning,
    TaskScheduler.Default)

3.一些坑

如下代碼.NET Core不支持哦,請使用Task.Factory.StartNew代替

Task.Factory.FromAsync(
    new Func<AsyncCallback, object, IAsyncResult>((cb, obj) => action.BeginInvoke(biz, cb, obj)),
    new Action<IAsyncResult>(ar => action.EndInvoke(ar)), null)

參考

The danger of TaskCompletionSource class

瞭解 .NET 的默認 TaskScheduler 和線程池(ThreadPool)設置,避免讓 Task.Run 的性能急劇下降

.NET 中當心嵌套等待的 Task,它可能會耗盡你線程池的現有資源,出現相似死鎖的狀況

.NET 中使用 TaskCompletionSource 做爲線程同步互斥或異步操做的事件

定義一組抽象的 Awaiter 的實現接口,你下次寫本身的 await 可等待對象時將更加方便

.NET 除了用 Task 以外,如何本身寫一個能夠 await 的對象?

.NET 中什麼樣的類是可以使用 await 異步等待的?

Asynchronous I/O in C#: I/O Completion Ports

Asynchronous I/O in C#: I/O Completion Ports

Migrating Delegate.BeginInvoke Calls for .NET Core

聲明

本文采用知識共享署名-非商業性使用-相同方式共享 2.5 中國大陸許可協議進行許可,發表在CSDN博客園,歡迎讀者轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接!請讀者/爬蟲們尊重版權

相關文章
相關標籤/搜索