.NET多執行緒(五)非同步操作

weixin_34402408發表於2017-03-12

5、非同步操作

5.1 非同步操作基礎

非同步操作發展歷史,APM模式,EAP模式,TPL模式

.NET 1.0

System.Threading.Thread
適用耗時操作、特殊操作、低優先順序操作,預設前臺

System.Threading.ThreadPool
適合短時操作,執行緒池執行緒預設後臺

# APM 非同步操作模式

.NET 2.0

Thread 構造支援 ParameterizedThreadStart 傳引數

匿名方法 delegate,閉包

ParameterizedThreadStart start = delegate(object obj) { };

同步上下文 SynchronizationContext
主要用在桌面UI應用 Send(同步) or Post(非同步)

# EAP 非同步操作模式

.NET 3.5

拉姆達表示式

泛型委託 Action 無返回結果,Func 最後必須結果

Action a1 = new Action(() => { });
Action<string> a2 = new Action<string>((s) => { });
Func<string> f1 = new Func<string>(() => { return ""; });
Func<int, string> f2 = new Func<int, string>((n) => { return n.ToString(); });

.NET 4.0

執行緒池執行緒最大數量,是根據電腦記憶體來計算的

優化執行緒池工作項排序
在 .net 4.0 以前,執行緒池的工作項,採用連結串列排隊
現在CPU都是多核處理器,假設現在有很多工作項
出現的問題:
(1)連結串列結構會存在很多引用,對垃圾回收影響很大
(2)連結串列是按順序操作,多核CPU真正的併發受到影響
在 .net 4.0 重新設計工作項排隊結構
陣列+連結串列
陣列元素對應工作項引用
(1)引用減少了
(2)現在是運算元組元素

# TPL 非同步操作模式

5.2 非同步操作模式

(1)APM 模式 Asynchronous Programming Model

2個方法 Begin/End,1個 IAsyncResult

必須呼叫 End,即使不需要返回結果,因為 End 會把執行緒的異常丟擲來
呼叫 End 加 try/catch
呼叫 Begin 之後,應當避免直接呼叫 End,因為 End 會等待結果,可能無限等待

APM 獲取結果

(1)輪詢是否完成

主要使用 System.Windows.Forms.Timer
輪詢 IAsyncResult 的 IsCompleted,並呼叫 End 獲取結果

(2)等待完成,IAsyncResult 的 AsyncWaitHandle 可以設定超時

直接呼叫 End,可能因為執行緒死鎖等,無限等待
使用 AsyncWaitHandle 可以設定超時,但是超時了就不會呼叫 End
不呼叫 End 就意味著執行緒的,異常可能沒捕獲,資源可能洩露
所以 AsyncWaitHandle 並不完美

(3)完成時回撥,AsyncCallback

這裡有個問題,就是回撥並不是在UI執行緒,如果要更新UI控制元件,那就不可以

static void Main(string[] args)
{
    HelloDelegate helloDelegate = new HelloDelegate(Hello);
    helloDelegate.BeginInvoke(Callback, helloDelegate);
    Console.ReadLine();
}
static void Callback(IAsyncResult ar)
{
    HelloDelegate helloDelegate = ar.AsyncState as HelloDelegate;
    try
    {
        string s = helloDelegate.EndInvoke(ar);
        Console.WriteLine(s);
    }
    catch (Exception) { }
}
static string Hello()
{
    return "hello";
}
public delegate string HelloDelegate();

APM 其他事

.NET 框架的一些類已經實現了 APM 模式
例如:使用 I/O thread 的 WebRequest,Stream,Socket,SqlCommand,MessageQueue 等

委託內在支援 APM 模式,使用(worker thread)

(2)EAP 模式 Event-Based Asynchronous Pattern

1個非同步Async方法,1個Completed事件

static void Main(string[] args)
{
    WebClient webClient = new WebClient();
    webClient.DownloadDataCompleted += delegate(object sender, DownloadDataCompletedEventArgs e)
    {
        try
        {
            byte[] result = e.Result;
        }
        catch (Exception) { }
    };
    webClient.DownloadDataAsync(new Uri(""));
}

在獲取 Result 的時候, try/catch
EAP 有個問題,如果發起多個非同步請求,在完成事件裡,需要區分結果來自哪個非同步操作呢

(3)TPL 模式 Task Parallel Library

基於 System.Threading.Tasks.Task
實現標準的取消執行緒,報告執行緒進度操作

Task 本質代表未來的操作

Task task = new Task(() =>
{
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    throw new Exception("error");
});
task.Start();
task.ContinueWith((t) =>
{
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
    Console.WriteLine(t.Exception.InnerException.Message);
}, TaskContinuationOptions.OnlyOnFaulted);
Console.ReadLine();

相關文章