1. 程式人生 > 實用技巧 >徹底搞懂C#非同步程式設計 async和await的原理

徹底搞懂C#非同步程式設計 async和await的原理

1.前提

熟練掌握Task並行程式設計。

2.用Task並行解釋async和await非同步

因為控制檯有多執行緒操作的優化,因此這裡選擇winform來做示例。

測試程式碼如下所示:
有三個textbox,一個button

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TestAsyncAwait
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Button1_Click(object sender, EventArgs e)
        {
            TestAsync();

            textBox3.Text = "333";
        }


        private async void TestAsync()
        {
            //Thread.Sleep(5000);//依然阻塞

            await Task.Run(() =>
            {
                Thread.Sleep(2000);

                this.Invoke((EventHandler)delegate { textBox1.Text = "1"; });

                Thread.Sleep(2000);

            });


            this.Invoke((EventHandler)delegate { textBox2.Text = "22"; });
        }

    }
}

顯示的順序是:333,1,22

如果在設定textbox顯示內容之前,通過Thread.CurrentThread.ManagedThreadId屬性來獲取當前執行緒ID。

可以得到textbox3所在為主執行緒,await之前也在主執行緒,await中和await後為新執行緒,這也是為什麼在textbox1和textbox2的text加上invoke的原因。

簡單來時,實際上async和await就是表示,遇到await之後,函式直接返回,然後剩下的部分等同於在一個新執行緒中執行。

使用Task並行程式設計的解釋程式碼如下,將button按鈕的click事件與TestAsync函式統一成TestTask函式

        private void TestTask()
        {
            Task.Run(() => 
            {
                Task task = Task.Run(() =>
                {
                    Thread.Sleep(2000);

                    this.Invoke((EventHandler)delegate { textBox1.Text = "1"; });

                    Thread.Sleep(2000);
                });

                Task.WaitAll(task);

                this.Invoke((EventHandler)delegate { textBox2.Text = "22"; });
            });

            textBox3.Text = "333";
        }

當然,上述程式碼也不完全等價async和await,只不過在實現功能上來說,沒有差別。

具體的差別表現為,waitall之前的執行緒與waitall之後所線上程不在同一個執行緒。這個差別也揭示了async和await的另外一個優勢,那就是節約執行緒,內部實現了執行緒池優化。

3.總結
如果你懂得Task並行程式設計或者Thread多執行緒程式設計,其實async和await的原理是不難的,沒有什麼神乎其神的操作。

async和await作為C#非同步程式設計的語法糖,具有無可匹敵的優勢,但是很多時候很多人不能理解用法,相比較而言直接使用Task並行程式設計會更加易懂。

我的建議是,如果是新專案可以使用async和await,讓自己的程式碼更簡潔;如果是老專案維護,建議還是使用Task的方式維護,容易讀懂。