關於async和await的一些誤區

微軟的MSDN說async和await是「異步」,可是很多人(包括筆者本身)有一些誤區須要澄清:爲何await語句以後沒有執行?不是異步嗎?多線程

  【示例代碼】異步

public partial class Form1 : Form
    {
        public async Task Processing()
        {
            await Task.Delay(5000);
            label1.Text = "Succuessful";
        }
        public Form1()
        {
            InitializeComponent();
            
        }
        private async void button1_Click(object sender, EventArgs e)
        {
            await Processing();
            MessageBox.Show("Button's event completed");
        }
    }

不少人(包括筆者)一開始會以爲異步好像相似多線程同樣,到await的時候會在後臺先開啓一個線程執行任務,隨後主線程(這裏是UI線程)將自動執行後面的部分(即彈出「Button's event completed」的消息框)。async

其實這個理解是錯誤的。async和await的本質實際上是「yield return」和「LINQ」的「迭代式」等待。咱們應該清楚一點:那就是你寫了LINQ語句:spa

var results = from ……
              select ……;

foreach(var r in results)
{
  ……
}

當你下斷點你會發覺results並不會當即執行,直到使用到results的地方(例子中也就是foreach這裏)纔會被執行(此時黃色跟蹤調試的光棒又會折回到var results……這裏,而後等到results執行完畢以後才真正進入foreach進行執行)。.net

因此,async/await和LINQ的這種「迭代式」的「異步操做」是殊途同歸的。只不過async/await本質是返回一個Task而已,而Task又是異步的(由於Task本質就是一個線程),因此真正執行到(使用到async方法的時候)帶有await的方法的時候,後臺纔會真正開啓一個線程去執行任務。此時主線程會等待這個Task線程直到其執行完畢(IsComplete屬性爲True爲止)。因此界面是不會卡頓的。線程

因此,await是Task的異步等待而已,並非咱們所謂的「異步操做」;拿它和LINQ做對比,你會發現LINQ執行順序和它一致,只不過LINQ沒有異步等待(固然沒有!又沒有開啓線程啥的……)。調試

咱們進一步能夠這樣對比:code

LINQ:變量 = LINQ語句(表達式)orm

           等到使用LINQ變量的時候才折返到LINQ語句處真正執行LINQ語句。blog

異步等待:變量 = 異步方法

            等到使用await+異步方法的時候纔會折返到該異步方法處,開啓線程真正執行異步方法,主線程被掛起(但不會形成界面死掉),直至子線程Task任務徹底執行完畢爲止。

在LINQ中,你若是須要當即執行,可使用擴展方法:

var results = (from ……
              select ……).ToList();

由於當即使用到了這個LINQ語句,因此會被當即執行。

一樣地,異步等待也能夠變成相似Wait同樣的同步等待:

private async void button1_Click(object sender, EventArgs e)
        {
            Processing().GetAwaiter().GetResult();
            MessageBox.Show("Button's event completed");
        }

由於Processing原本就返回Task,固然也可使用Wait進行同步等待。

參考文獻:http://blog.csdn.net/ma_jiang/article/details/37884915

相關文章
相關標籤/搜索