.NET異步和多線程系列(六)- async/await
本文是.NET異步和多線程系列的第六章,本章主要對(duì)之前介紹過(guò)的async/await做一些補(bǔ)充說(shuō)明。
下面我們直接來(lái)看下代碼和運(yùn)行結(jié)果:

using System;
using System.Threading;
using System.Threading.Tasks;
namespace MyAsyncAwait
{
///
/// await/async 是C#保留關(guān)鍵字,通常是成對(duì)出現(xiàn),語(yǔ)法糖。
///
/// 主線程調(diào)用async/await方法,主線程遇到await返回執(zhí)行后續(xù)動(dòng)作,
/// await后面的代碼會(huì)等著Task任務(wù)的完成后再繼續(xù)執(zhí)行
/// 其實(shí)就像把a(bǔ)wait后面的代碼包裝成一個(gè)ContinueWith的回調(diào)動(dòng)作
/// 然后這個(gè)回調(diào)動(dòng)作可能是Task線程,也可能是新的子線程,也可能是主線程
///
/// 一個(gè)async方法,如果沒(méi)有返回值,可以方法聲明返回Task
/// await/async能夠用同步的方式編寫(xiě)代碼,但又是非阻塞的。
///
/// async方法在編譯后會(huì)生成一個(gè)狀態(tài)機(jī)(實(shí)現(xiàn)了IAsyncStateMachine接口)
///
class Program
{
static void Main(string[] args)
{
Console.WriteLine($"當(dāng)前主線程開(kāi)始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
AwaitAsyncClass.TestShow();
Console.WriteLine($"當(dāng)前主線程結(jié)束 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Console.ReadKey();
}
}
///
/// await/async關(guān)鍵字 語(yǔ)法糖
/// await/async 要么不用 要么用到底
///
public class AwaitAsyncClass
{
public static void TestShow()
{
Test();
}
private async static Task Test()
{
Console.WriteLine($"Test開(kāi)始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Task<long> t = SumAsync();
Console.WriteLine($"遇到await主線程回來(lái)干活了 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
{
long lResult = await t; //await后面的代碼會(huì)由線程池的線程執(zhí)行,非阻塞。
Console.WriteLine($"最終得到的lResult={lResult}");
}
{
//t.Wait(); //主線程等待Task的完成,阻塞的
//long lResult = t.Result; //訪問(wèn)Result,主線程等待Task的完成,阻塞的,效果跟t.Wait()一樣
//Console.WriteLine($"最終得到的lResult={lResult}");
}
Console.WriteLine($"Test結(jié)束 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
}
///
/// 帶返回值的Task
/// 要使用返回值就一定要等子線程計(jì)算完畢
///
private static async Task<long> SumAsync()
{
Console.WriteLine($"SumAsync start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
long result = 0;
//await后面的代碼會(huì)等著Task任務(wù)的完成后再繼續(xù)執(zhí)行
//其實(shí)就像把a(bǔ)wait后面的代碼包裝成一個(gè)ContinueWith的回調(diào)動(dòng)作
//然后這個(gè)回調(diào)動(dòng)作可能是Task線程,也可能是新的子線程,也可能是主線程
await Task.Run(() =>
{
for (int k = 0; k < 2; k++)
{
Console.WriteLine($"SumAsync 第1個(gè) await Task.Run k={k} ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(1000);
}
for (long i = 0; i < 999_999_999; i++)
{
result += i;
}
});
Console.WriteLine($"SumAsync 第1個(gè) await Task.Run的后續(xù)任務(wù)開(kāi)始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
await Task.Run(() =>
{
for (int k = 0; k < 2; k++)
{
Console.WriteLine($"SumAsync 第2個(gè) await Task.Run k={k} ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(1000);
}
for (long i = 0; i < 999_999_999; i++)
{
result += i;
}
});
Console.WriteLine($"SumAsync 第2個(gè) await Task.Run的后續(xù)任務(wù)開(kāi)始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
await Task.Run(() =>
{
for (int k = 0; k < 2; k++)
{
Console.WriteLine($"SumAsync 第3個(gè) await Task.Run k={k} ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Thread.Sleep(1000);
}
for (long i = 0; i < 999_999_999; i++)
{
result += i;
}
});
Console.WriteLine($"SumAsync end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
return result;
}
}
}

運(yùn)行結(jié)果如下:

仔細(xì)觀察結(jié)果會(huì)發(fā)現(xiàn):
主線程調(diào)用async/await方法,主線程遇到await后會(huì)返回執(zhí)行后續(xù)動(dòng)作;
await后面的代碼會(huì)等著Task任務(wù)的完成后再繼續(xù)執(zhí)行,其實(shí)就像把a(bǔ)wait后面的代碼包裝成一個(gè)ContinueWith的回調(diào)動(dòng)作;
然后這個(gè)回調(diào)動(dòng)作可能是Task線程,也可能是新的子線程,也可能是主線程;
await/async能夠用同步的方式編寫(xiě)代碼,但又是非阻塞的。
下面我們調(diào)整下Test方法后再運(yùn)行(紅色的為調(diào)整部分):

private async static Task Test()
{
Console.WriteLine($"Test開(kāi)始 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
Task<long> t = SumAsync();
Console.WriteLine($"遇到await主線程回來(lái)干活了 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
{
//long lResult = await t; //await后面的代碼會(huì)由線程池的線程執(zhí)行,非阻塞。
//Console.WriteLine($"最終得到的lResult={lResult}");
}
{
//t.Wait(); //主線程等待Task的完成,阻塞的
long lResult = t.Result; //訪問(wèn)Result,主線程等待Task的完成,阻塞的,效果跟t.Wait()一樣
Console.WriteLine($"最終得到的lResult={lResult}");
}
Console.WriteLine($"Test結(jié)束 ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
}

調(diào)整后運(yùn)行結(jié)果如下:

仔細(xì)觀察結(jié)果會(huì)發(fā)現(xiàn):
訪問(wèn)Result,主線程會(huì)等待Task的完成,阻塞的。
其實(shí)async方法在編譯后會(huì)生成一個(gè)狀態(tài)機(jī)(實(shí)現(xiàn)了IAsyncStateMachine接口),有興趣的可以自行去了解下。
至此本文就介紹完了,有興趣的還可以看下我之前寫(xiě)過(guò)一篇也是關(guān)于async/await的文章:https://www.cnblogs.com/xyh9039/p/11391507.html
?
Demo源碼:
鏈接:https://pan.baidu.com/s/1jnG5IpteuKCdmF6-tr--cA
提取碼:3onm
此文由博主精心撰寫(xiě)轉(zhuǎn)載請(qǐng)保留此原文鏈接:https://www.cnblogs.com/xyh9039/p/13622122.html
版權(quán)聲明:如有雷同純屬巧合,如有侵權(quán)請(qǐng)及時(shí)聯(lián)系本人修改,謝謝!??!
版權(quán)申明:本文來(lái)源于網(wǎng)友收集或網(wǎng)友提供,如果有侵權(quán),請(qǐng)轉(zhuǎn)告版主或者留言,本公眾號(hào)立即刪除。
