C# 非同步程式設計

綠龍術士發表於2018-03-21

使用非同步程式設計,方法呼叫時在後臺執行,並且不會阻塞呼叫執行緒。

非同步程式設計模型Async Patterns Model(APM)

非同步模式定義了BeginXXX和EndXXX方法。BeginXXX方法接受其同步方法的所有輸入引數,EndXXX方法使用同步方法的所有輸出引數,並按照同步方法的返回型別來返回結果。

            //非同步模式定義了BeginXXX和EndXXX方法
            WebRequest request = WebRequest.Create("http://www.baidu.com");
            var result = request.BeginGetResponse((obj) => {
            }, null);
            var resp = request.EndGetResponse(result);

 

基於事件的非同步模式Event-based Async Pattern(EAP)

 

基於事件的非同步模式定義了一個帶有“Async”字尾的方法。例如,對於同步方法DownloadString,WebClient提供了非同步方法DownloadStringAsync。並且你需要編寫DownloadStringCompleted事件,這個事件會在非同步方法完成後呼叫。

基於事件的非同步方法優勢在於易於使用。但是,在自定義類中這個模式就沒有這麼簡單了

            //基於事件的非同步模式定義了一個帶有“Async”字尾的方法
            var client = new WebClient();
            client.Encoding = Encoding.UTF8;
            client.DownloadStringCompleted += (sender1, e1) =>
            {
                var resp = e1.Result;

            };
            client.DownloadStringAsync(new Uri("http://www.baidu.com"));

 

基於任務的非同步模式Task-based Async Pattern(TAP)

 

該模式定義一個帶有“Async”字尾的方法,並返回一個Task型別。例如WebClient提供的基於任務的非同步方法DownloadStringTaskAsync,該方法返回一個Task<string>,可以用string類接收它,並使用await關鍵字,await關鍵字會解除執行緒(UI執行緒)的阻塞,完成其他任務。

            //基於任務的非同步模式
            var client = new WebClient();
            client.Encoding = Encoding.UTF8;
            string resp = await client.DownloadStringTaskAsync("http://www.baidu.com");

 

async和await關鍵字只是編譯器的功能。編譯器會用Task類建立程式碼。如果不使用者兩個關鍵字,也可以用C# 4.0和Task類的方法來實現同樣的功能,只是沒有那麼方便。

 

async修飾符只能用於返回.NET型別的Task或void方法,以及Window執行庫的IAsyncOperation。

Task類的ContinueWith方法定義了任務完成後就呼叫的程式碼。指派給ContinueWith方法的委託接收已完成的任務作為引數傳入,使用Result屬性可以訪問任務返回的結果。

        public string Greeting(string name)
        {
            //同步任務
            Task.Delay(2000).Wait();//等同於Thread.Sleep()
            return "hello " + name;
        }
        public Task<string> GreetingAsync(string name)
        {
            //非同步任務
            return Task.Run<string>(() => {
                return Greeting(name);
            });
        }
            //延續任務
            Task<string> task = GreetingAsync("Xie");
            task.ContinueWith(t => {
                var msg = t.Result + " !";
                MessageBox.Show(msg);
            });

Task類定義了WhenAll和WhenAny組合器。從WhenAll方法返回的Task,是在所有傳入方法的任務都完成了才會返回Task。從WhenAny方法返回的Task,是在其中一個傳入方法完成了就會返回Task。

            Task<string> task = GreetingAsync("Wang");//耗時2秒
            Task<string> task2 = GreetingAsync2("Bai");//耗時6秒
            //其中一個執行緒執行完畢就會繼續執行
            //var task3 = await Task.WhenAny(task, task2);
            //MessageBox.Show(task3.Result);
            //當所有執行緒執行完才會繼續執行
            var task3 = await Task.WhenAll(task, task2);
            MessageBox.Show(task3[0] + "," + task3[1]);

想了解更多關於C# 6與.NET Core的知識請參考:《C#高階程式設計》

相關文章