最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

Task、await、async的使用

2023-06-16 11:32 作者:坤坤私人助產(chǎn)師  | 我要投稿

異步與同步》

異步:不阻塞線程

同步:阻塞線程

異步方法、同步方法》

即某一方法在執(zhí)行時如果后續(xù)的代碼不能執(zhí)行只有等待該方法執(zhí)行完成后才能繼續(xù)執(zhí)行(造成UI卡死現(xiàn)象)的方法稱之為同步方法,反之如果該方法在執(zhí)行階段后續(xù)代碼依舊可以執(zhí)行,這個方法稱之為異步方法。

多線程編寫》

Thread》

之前使用最多的一種。

看一個例子【輸出1到10每秒輸出一個數(shù)字】

? ? ? ?static void Main(string[] args) ? ? ? ?{ ??

? ? ? ? ?Console.WriteLine("Hello World!"); ? ? ? ? ? ?Thread th = new Thread(() => ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?for (int index = 1; index <11; index++) ? ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ? ?Console.WriteLine(index); ? ? ? ? ? ? ? ? ? ?Thread.Sleep(1000); ? ? ? ? ? ? ? ?} ? ? ? ? ? ?}); ? ? ? ? ? ?th.Start(); ? ? ? ? ? ?Console.ReadLine(); ? ? ? ?}

上述是最基本的使用,關(guān)于Thread不多做介紹。

ThreadPool》

ThreadPool(線程池)是一種并發(fā)編程的概念,它是一組可重復(fù)使用的線程,用于執(zhí)行多個任務(wù)。線程池管理著一個線程隊列,其中包含多個線程,這些線程可以執(zhí)行任務(wù)。

使用線程池的好處是可以避免頻繁地創(chuàng)建和銷毀線程,從而提高程序的性能和效率。線程池可以控制并發(fā)線程的數(shù)量,避免系統(tǒng)資源被過度占用。當(dāng)有任務(wù)需要執(zhí)行時,線程池中的線程會被分配給任務(wù),并在任務(wù)完成后返回線程池,等待下一個任務(wù)的到來。

線程池通常由以下幾個組件組成:

  1. 任務(wù)隊列:用于存儲待執(zhí)行的任務(wù)。

  2. 線程池管理器:用于創(chuàng)建、銷毀和管理線程池中的線程。

  3. 工作線程:線程池中的線程,用于執(zhí)行任務(wù)。它們從任務(wù)隊列中獲取任務(wù)并執(zhí)行,執(zhí)行完任務(wù)后返回線程池等待下一個任務(wù)。

一個案例:

? ? ? ?static void Main(string[] args) ? ? ? ?{ ? ? ? ? ? ?Console.WriteLine("Hello World!"); ? ? ? ? ? ?for (int i = 1; i <= 10; i++) ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?ThreadPool.QueueUserWorkItem(new WaitCallback((t) => { ? ? ? ? ? ? ? ? ? ?Console.WriteLine($"這是第{t}個任務(wù)~"); ? ? ? ? ? ? ? ?}), i); ? ? ? ? ? ?} ? ? ? ? ? ?Console.ReadLine(); ? ? ? ?}

ThreadPool幾乎沒用過(慚愧?。?/p>

Task》

重點介紹一下Task

Task與Thread相比有哪些優(yōu)缺點?

Task(任務(wù))和Thread(線程)是并發(fā)編程中常用的兩個概念,它們有各自的優(yōu)缺點。

優(yōu)點:

  1. 靈活性:Task比Thread更加靈活。Task通常是以異步的方式執(zhí)行,可以在需要時啟動、暫停、取消或等待任務(wù)的完成。而Thread是同步執(zhí)行的,一旦啟動就會一直執(zhí)行直到結(jié)束。

  2. 資源消耗:Task比Thread消耗的資源更少。Task利用線程池來執(zhí)行任務(wù),可以重用線程,避免頻繁創(chuàng)建和銷毀線程的開銷,從而減少系統(tǒng)資源的消耗。

  3. 異常處理:Task可以更好地處理異常。Task可以通過異常處理機制捕獲和處理任務(wù)中的異常,而Thread需要開發(fā)者自行處理異常。

缺點:

  1. 復(fù)雜性:相比于Thread,Task的使用可能更加復(fù)雜

Task的創(chuàng)建》還是【輸出1到10每秒輸出一個數(shù)字】為例

方法1

如下創(chuàng)建方式

? ? ? ?static void Main(string[] args) ? ? ? ?{ ? ? ? ? ? ?Console.WriteLine("Hello World!"); ? ? ? ? ? ?Task tk = new Task(()=> ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?for (int i = 1; i <= 10; i++) ? ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ? ?Thread.Sleep(1000); ? ? ? ? ? ? ? ? ? ?Console.WriteLine(i); ? ? ? ? ? ? ? ?} ? ? ? ? ? ?}); ? ? ? ? ? ?tk.Start(); ? ? ? ? ? ?Console.ReadLine(); ? ? ? ?}

方法二:

? ? ? ?static void Main(string[] args) ? ? ? ?{ ? ? ? ? ? ?Console.WriteLine("Hello World!"); ? ? ? ? ? ?Task tk = Task.Factory.StartNew(() => ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?for (int i = 1; i <= 10; i++) ? ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ? ?Thread.Sleep(1000); ? ? ? ? ? ? ? ? ? ?Console.WriteLine(i); ? ? ? ? ? ? ? ?} ? ? ? ? ? ?}); ? ? ? ? ? ?Console.ReadLine(); ? ? ? ?}

可以看到我并沒有使用tk.Start();來啟動,因為這種創(chuàng)建方式當(dāng)創(chuàng)建好后就表示啟動(窗機即啟動)。

  1. Task tk = new Task():這種方式只是創(chuàng)建了一個 Task 對象,但并沒有立即啟動它。需要調(diào)用 tk.Start() 方法來手動啟動任務(wù)。這種方式適用于需要手動控制任務(wù)的啟動時機,或者需要在任務(wù)啟動前進行一些其他操作的情況。

  2. Task.Factory.StartNew():這種方式創(chuàng)建并立即啟動一個 Task 對象。它使用 Task 類的工廠方法來創(chuàng)建任務(wù),并自動啟動任務(wù)。這種方式更為簡潔,適用于直接啟動任務(wù)且不需要手動控制啟動時機的情況。

方法三:

? ? ? ?static void Main(string[] args) ? ? ? ?{ ? ? ? ? ? ?Console.WriteLine("Hello World!"); ? ? ? ? ? ?Task tk = Task.Run(() => ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?for (int i = 1; i <= 10; i++) ? ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ? ?Thread.Sleep(1000); ? ? ? ? ? ? ? ? ? ?Console.WriteLine(i); ? ? ? ? ? ? ? ?} ? ? ? ? ? ?}); ? ? ? ? ? ?Console.ReadLine(); ? ? ? ?}

Task tk = Task.Run():這種方式是.NET Framework 4.5及更高版本引入的簡化創(chuàng)建和啟動任務(wù)的方法。它會創(chuàng)建并立即啟動一個 Task 對象,類似于 Task.Factory.StartNew(),但是更為簡潔。它會自動使用默認(rèn)的 TaskScheduler 來調(diào)度任務(wù),并且返回一個已啟動的 Task 對象。

關(guān)于await、async》

這兩玩意是干啥的?

解釋這個問題先看一下之前寫的同步方法、與異步方法。

還是以【輸出1到10每秒輸出一個數(shù)字】為例說明。

同步方法最基本的寫法來完成這個需求:

static void Main(string[] args) ? ? ? ?{ ? ? ? ? ? ?Console.WriteLine("Hello World!"); ? ? ? ? ? ?for (int i = 1; i <= 10; i++) ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?Thread.Sleep(1000); ? ? ? ? ? ? ? ?Console.WriteLine(i); ? ? ? ? ? ?} ? ? ? ? ? ?Console.ReadLine(); ? ? ? ?}

執(zhí)行結(jié)果沒毛病,是每秒輸出一個。但是我代碼后面有一句[Console.ReadLine();]讀取用戶輸入的操作,在代碼輸出1-10期間我是不能輸入的因為這是同步方法,我的UI是卡死的(控制臺程序還不太能看出來卡死在大多數(shù)窗體應(yīng)用中非常明顯,這樣用戶體驗會非常差),所以來看看異步方法。

確保畫面不卡死的情況下完成這個需求:

? ? ? ?static void Main(string[] args) ? ? ? ?{ ? ? ? ? ? ?Console.WriteLine("Hello World!"); ? ? ? ? ? ?Task tk = Task.Factory.StartNew(() => ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?for (int i = 1; i <= 10; i++) ? ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ? ?Thread.Sleep(1000); ? ? ? ? ? ? ? ? ? ?Console.WriteLine(i); ? ? ? ? ? ? ? ?} ? ? ? ? ? ?}); ? ? ? ? ? ?Console.ReadLine(); ? ? ? ?}

當(dāng)數(shù)字在輸出階段我還是可以手動輸入內(nèi)容的,這樣就不會造成UI卡死的現(xiàn)象。

但是這并不是一個異步方法來完成的。

Task.Factory.StartNew 方法用于創(chuàng)建并啟動一個新的 Task 對象。然而,代碼中使用的是 Thread.Sleep 方法而不是 Task.Delay 方法來進行延遲,這意味著任務(wù)是通過線程阻塞來實現(xiàn)延遲的。

由于使用了 Thread.Sleep 方法,這個任務(wù)實際上是同步執(zhí)行的,而不是異步的。

使用異步方法來完成這個需求:

static void Main(string[] args) ? ? ? ?{ ? ? ? ? ? ?Console.WriteLine("Hello World!"); ? ? ? ? ? ?Task tk = Task.Factory.StartNew(async () =>//async 來修飾異步方法 ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?for (int i = 1; i <= 10; i++) ? ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ? ?await Task.Delay(1000);//await 表示等待異步執(zhí)行完成 ? ? ? ? ? ? ? ? ? ?Console.WriteLine(i); ? ? ? ? ? ? ? ?} ? ? ? ? ? ?}); ? ? ? ? ? ?Console.ReadLine(); ? ? ? ?}

上面是代碼(注釋部分先看一眼,后面解釋),下面是一些截圖

解釋一下異步方法中的awiat、async(重點)》

將上述方法小小的修改一下,先去掉await、async,如何用一個方法來實現(xiàn)一些:

? ? ? ?static void Main(string[] args) ? ? ? ?{ ? ? ? ? ? ?Console.WriteLine("Hello World!"); ? ? ? ? ? ? ? TaskSleep(); ? ? ? ? ? ?Console.ReadLine(); ? ? ? ?} ? ? ? ?public static void TaskSleep() ? ? ? ?{ ? ? ? ? ? ?for (int i = 1; i <= 10; i++) ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?Task.Delay(1000); ? ? ? ? ? ? ? ?Console.WriteLine(i); ? ? ? ? ? ?} ? ? ? ?}

我調(diào)用寫的TaskSleep來完成輸出,但是效果并不是一秒一個而是瞬間全部輸出,

這是因為Task.Delay()方法是一個異步方法,既然是異步方法,那么這個執(zhí)行就不會阻塞后面的輸出了,我要如何讓后面的輸出等待這個異步方法完成之后再去輸出?

await來了》

為了讓異步方法也可以實現(xiàn)類似于”阻塞“的效果就讓這個await來完成吧

再改一下上述代碼:

? ? ? ?static void Main(string[] args) ? ? ? ?{ ? ? ? ? ? ?Console.WriteLine("Hello World!"); ? ? ? ? ? ? ? TaskSleep(); ? ? ? ? ? ?Console.ReadLine(); ? ? ? ?} ? ? ? ?public static void TaskSleep() ? ? ? ?{ ? ? ? ? ? ?for (int i = 1; i <= 10; i++) ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?await Task.Delay(1000); ? ? ? ? ? ? ? ?Console.WriteLine(i); ? ? ? ? ? ?} ? ? ? ?}

報錯啊?

這時就要看async了

可以看到await只能用在異步方法中,所以要使用async來修飾方法位異步方法,再改代碼如下:

? ? ? ?static void Main(string[] args) ? ? ? ?{ ? ? ? ? ? ?Console.WriteLine("Hello World!"); ? ? ? ? ? ? ? TaskSleepAsync(); ? ? ? ? ? ?Console.ReadLine(); ? ? ? ?} ? ? ? ?public static async Task TaskSleepAsync() ? ? ? ?{ ? ? ? ? ? ?for (int i = 1; i <= 10; i++) ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?await Task.Delay(1000); ? ? ? ? ? ? ? ?Console.WriteLine(i); ? ? ? ? ? ?} ? ? ? ?}

看一下效果是可以完成需求的標(biāo)準(zhǔn),一秒輸出一個的。

為什么TaskSleepAsync下面有個綠波浪線?

這是因為我的TaskSleepAsync是一個異步方法,但是卻沒有實現(xiàn)等待(await),也就是說并不會等待我的異步方法執(zhí)行完成再執(zhí)行后續(xù)代碼而是直接執(zhí)行后續(xù)代碼,這也就是為什么在輸出進行中時我還能輸入。

修改一些代碼讓這個問題看起來明顯一點:

如果后續(xù)的代碼要等待我異步方法執(zhí)行完后再執(zhí)行,但是我異步方法還沒開始輸出就輸出【異步方法執(zhí)行完成!】是不是很奇怪?

給這個異步方法加上await來試試

這下就沒問題了。

綜上所述,awiat、async就是原來修飾一個方法位異步方法的,await就是來等待這個異步方法完成的,使用await時被修改的方法必須是異步的,而且調(diào)用者本身也是由async所修飾的。

異步方法的返回值》

異步方法也可以有返回值如下:

如果不適應(yīng)await修飾時,返回類型就是一個Task<int>了!

因為沒有使用await修飾所以不會等待異步完成后執(zhí)行后續(xù)代碼,但是異步方法依舊是執(zhí)行的,這點可以從執(zhí)行結(jié)果看出來。

我還可以如下這樣,這時就可以看到等待的效果,而且a執(zhí)行的結(jié)果使用int接收也沒問題。

輸出1到10的內(nèi)容是在TaskSleepAsync方法中完成的。在TaskSleepAsync方法中,使用了Console.WriteLine(i)語句,在每次循環(huán)中輸出當(dāng)前的計數(shù)值。這意味著無論是否等待異步方法的完成,都會輸出10次計數(shù)。

int b = await a;語句只是等待異步方法的完成,并將返回的結(jié)果賦值給變量b。它并不會觸發(fā)Console.WriteLine(i)語句的執(zhí)行。

另一種:

a.Result表示等待異步方法TaskSleepAsync的完成,并獲取其返回的結(jié)果。通過使用a.Result,我們可以阻塞當(dāng)前線程,直到異步方法完成并返回結(jié)果。

a.Result和await都可以用于等待異步方法的完成并獲取其返回的結(jié)果,但它們有一些重要的區(qū)別。 阻塞 vs 非阻塞:使用a.Result會阻塞當(dāng)前線程,直到異步方法完成并返回結(jié)果。這意味著在等待期間,線程會被阻塞,無法執(zhí)行其他任務(wù)。而使用await關(guān)鍵字時,當(dāng)前線程會被釋放,可以執(zhí)行其他任務(wù),直到異步方法完成后再繼續(xù)執(zhí)行。

也就是說使用a.Result等待的話畫面會卡死,但是await不會


Task、await、async的使用的評論 (共 條)

分享到微博請遵守國家法律
达拉特旗| 容城县| 镇江市| 右玉县| 星子县| 城口县| 伊宁市| 腾冲县| 南木林县| 鹤峰县| 夏邑县| 赤壁市| 静乐县| 本溪市| 合川市| 剑川县| 舟曲县| 保德县| 平邑县| 金秀| 大新县| 龙南县| 舒兰市| 专栏| 汉川市| 太仓市| 彰化市| 磐石市| 佛学| 南华县| 五寨县| 图木舒克市| 禄丰县| 宾川县| 双城市| 阳朔县| 洪湖市| 厦门市| 濮阳市| 合江县| 金川县|