前言
自從C# 5.0時代引入async和await關(guān)鍵字后,異步編程就變得流行起來唆缴。尤其在現(xiàn)在的.NET Core時代奴饮,甚至如果你的代碼中沒有出現(xiàn)async或者await關(guān)鍵字,都會讓人感覺到很奇怪缝龄。
本篇文章將會先給大家?guī)硪粋€關(guān)于Async簡單的例子,然后再四種啟動線程的方法的對比中讓大家意識到為什么現(xiàn)在的大佬都偏愛Async await.
在這之前,我希望大家首先能知道下面這個事實(shí):
// < : 后者性能高于前者
Thread < ThreadPoll < Task < Async await
注:上述情況只在頻繁使用線程的情況下適用
Async await
方法使用Async修飾符修飾.
返回類型僅有三種: void,Task,Task<T>
方法內(nèi)部使用await關(guān)鍵字標(biāo)明開始執(zhí)行異步代碼
await標(biāo)志前的代碼是同步執(zhí)行,await標(biāo)志的方法是異步執(zhí)行,await標(biāo)志的方法后面的代碼相當(dāng)于"回調(diào)函數(shù)",在await標(biāo)志的異步方法后面執(zhí)行.
所以使用Async await異步編程之后代碼的執(zhí)行順序會變成下面這樣:
如果沒看懂上圖,也沒關(guān)系,我們再來看一個小例子:
下面?zhèn)€例子中,我用英文的輸出代表主線程的輸出,中文的輸出代表子線程的輸出
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Let`s Do This!");
Console.WriteLine("I am going to call my son.");
AsyncTask();//調(diào)用Async修飾的方法
Console.WriteLine("My son is busy now,and I will go on.");
Console.WriteLine("I`m done!");
Console.ReadLine();
}
//Async修飾的方法
public async Task AsyncTask()
{
Console.WriteLine($"我是方法AsyncTask");
var result= await WasteTime();
Console.WriteLine(result);
Console.WriteLine("我已經(jīng)干完了我應(yīng)該干的事情!");
}
private async Task<string> WasteTime()
{
return await Task.Run(() =>
{
Thread.Sleep(1);//避免Console.WriteLine執(zhí)行太快使整個程序執(zhí)行起來像是同步執(zhí)行的
Console.WriteLine("我開始異步執(zhí)行了!");
Console.WriteLine("可是我啥都不想干,還是等個五秒鐘就跟主線程說我做好了吧");
Thread.Sleep(5000);
return "我異步執(zhí)行完了";
});
}
}
運(yùn)行效果如下:
為什么Thread < ThreadPoll
Thread默認(rèn)創(chuàng)建的是前臺線程,每次初始化一個Thread的示例,就會創(chuàng)建一個新的線程!
ThreadPoll默認(rèn)創(chuàng)建的是后臺線程,每次啟用線程會從線程池尋找空閑的線程,如果找到了,就會調(diào)用這個空閑的線程,而不是直接創(chuàng)建一個新的的線程.
而每次創(chuàng)建一個線程,起碼約消耗1M的內(nèi)存.
因此在需要開啟大量線程的情況下,相比于Thread,ThreadPoll具有減少開啟新線程消耗的資源,以及統(tǒng)一管理線程的優(yōu)勢!
為什么ThreadPoll < Task
ThreadPool使用的是線程池全局隊列寨闹,全局隊列中的線程依舊會存在競爭共享資源的情況胶坠,從而影響性能。
Task基于ThreadPool實(shí)現(xiàn),相當(dāng)于ThreadPoll的優(yōu)化版.它不再使用線程池的全局隊列繁堡,而是使用的本地隊列,使線程之間的資源競爭減少沈善。同時Task提供了豐富的API來管理線程、控制椭蹄。但是相對前面的兩種耗內(nèi)存闻牡,Task依賴于CPU對于多核的CPU性能遠(yuǎn)超前兩者,單核的CPU三者的性能沒什么差別绳矩。
為什么Task < Async await
1.舉個例子:
現(xiàn)在需要實(shí)現(xiàn)一個,異步寫數(shù)據(jù)庫,寫成功之后需要在頁面上彈出一個小窗提示.
如果你用task.result來實(shí)現(xiàn)的話,那么在獲取到結(jié)果之前,task會使你的項(xiàng)目進(jìn)去一個阻塞狀態(tài).也就是說在小窗彈出來之前,你的程序會一直卡主!從而形成異步編程中的同步阻塞
而Async await則不會發(fā)生這種情況.你需要做的僅僅只是在await修飾的方法后面調(diào)一個彈出小窗的方法而已.也就是傳說中的異步阻塞
2.Async await風(fēng)格的編程會使代碼看起來更像是同步代碼,也就更像清新移動更通俗.
結(jié)語
其實(shí)在你理解了異步編程的基礎(chǔ)上,Async await并沒有什么復(fù)雜的.明白了例子中帶返回值的寫法,那別的兩種返回類型應(yīng)該也是信手拈來.從表面上看來,它的編碼風(fēng)格跟同步方法非常相似,以至于新手看到會有一種"我*,這不是同步方法嗎"的感覺,從而給心理上造成了一定負(fù)擔(dān),使自己覺得Async很難,所以懶得去研究了.
最后,如果本篇文章給您帶來了幫助,就點(diǎn)個贊再走唄~