微軟的MSDN說(shuō)async和await是“異步”,但是不少人(包括筆者自己)有一些誤區(qū)需要澄清:為什么await語(yǔ)句之后沒(méi)有執(zhí)行?不是異步嗎?
【示例代碼】
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"); } }
很多人(包括筆者)一開(kāi)始會(huì)覺(jué)得異步好像類(lèi)似多線(xiàn)程一樣,到await的時(shí)候會(huì)在后臺(tái)先開(kāi)啟一個(gè)線(xiàn)程執(zhí)行任務(wù),隨后主線(xiàn)程(這里是UI線(xiàn)程)將自動(dòng)執(zhí)行后面的部分(即彈出“Button's event completed”的消息框)。
其實(shí)這個(gè)理解是錯(cuò)誤的。async和await的本質(zhì)其實(shí)是“yield return”和“LINQ”的“迭代式”等待。我們應(yīng)該清楚一點(diǎn):那就是你寫(xiě)了LINQ語(yǔ)句:
var results = from …… select ……;foreach(var r in results){ ……}
當(dāng)你下斷點(diǎn)你會(huì)發(fā)覺(jué)results并不會(huì)立即執(zhí)行,直到使用到results的地方(例子中也就是foreach這里)才會(huì)被執(zhí)行(此時(shí)黃色跟蹤調(diào)試的光棒又會(huì)折回到var results……這里,然后等到results執(zhí)行完畢之后才真正進(jìn)入foreach進(jìn)行執(zhí)行)。
所以,async/await和LINQ的這種“迭代式”的“異步操作”是異曲同工的。只不過(guò)async/await本質(zhì)是返回一個(gè)Task而已,而Task又是異步的(因?yàn)門(mén)ask本質(zhì)就是一個(gè)線(xiàn)程),所以真正執(zhí)行到(使用到async方法的時(shí)候)帶有await的方法的時(shí)候,后臺(tái)才會(huì)真正開(kāi)啟一個(gè)線(xiàn)程去執(zhí)行任務(wù)。此時(shí)主線(xiàn)程會(huì)等待這個(gè)Task線(xiàn)程直到其執(zhí)行完畢(IsComplete屬性為T(mén)rue為止)。所以界面是不會(huì)卡頓的。
所以,await是Task的異步等待而已,并不是我們所謂的“異步操作”;拿它和LINQ作對(duì)比,你會(huì)發(fā)現(xiàn)LINQ執(zhí)行順序和它一致,只不過(guò)LINQ沒(méi)有異步等待(當(dāng)然沒(méi)有!又沒(méi)有開(kāi)啟線(xiàn)程啥的……)。
我們進(jìn)一步可以這樣對(duì)比:
LINQ:變量 = LINQ語(yǔ)句(表達(dá)式)
等到使用LINQ變量的時(shí)候才折返到LINQ語(yǔ)句處真正執(zhí)行LINQ語(yǔ)句。
異步等待:變量 = 異步方法
等到使用await+異步方法的時(shí)候才會(huì)折返到該異步方法處,開(kāi)啟線(xiàn)程真正執(zhí)行異步方法,主線(xiàn)程被掛起(但不會(huì)造成界面死掉),直至子線(xiàn)程Task任務(wù)完全執(zhí)行完畢為止。
在LINQ中,你如果需要立即執(zhí)行,可以使用擴(kuò)展方法:
var results = (from …… select ……).ToList();
因?yàn)榱⒓词褂玫搅诉@個(gè)LINQ語(yǔ)句,所以會(huì)被立即執(zhí)行。
同樣地,異步等待也可以變成類(lèi)似Wait一樣的同步等待:
private async void button1_Click(object sender, EventArgs e) { Processing().GetAwaiter().GetResult(); MessageBox.Show("Button's event completed"); }
因?yàn)镻rocessing本來(lái)就返回Task,當(dāng)然也可以使用Wait進(jìn)行同步等待。
參考文獻(xiàn):http://blog.csdn.net/ma_jiang/article/details/37884915
|
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注