日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

一文说通C#中的异步编程补遗

發布時間:2023/12/4 C# 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一文说通C#中的异步编程补遗 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前文寫了關于C#中的異步編程。后臺有無數人在討論,很多人把異步和多線程混了。

文章在這兒:一文說通C#中的異步編程

所以,本文從體系的角度,再寫一下這個異步編程。

?

一、C#中的異步編程演變

1. 異步編程模型

這是C#中早期的異步模型,通過IAsyncResult接口來實現。

實現的代碼大體是這個樣子:

class?MyClass {IAsyncResult?BeginAction(para?...,?AsyncCallback?callback,?object?state);T?EndAction(IAsyncResult?async_result); }

這種方式在一些庫里還有保留,像FileSteam類里的BeginRead和EndRead方法組,就是這種方式。

編程時,不建議用這種方式。

2. 基于事件的異步模型

這是C#中間一個過渡時期的異步模型,核心是基于一個或多個事件、事件處理委托的派生類型,是一種使用多線程的模式。

這個模式在類庫里,多用在Winform/WPF中的組件的事件處理,你可以隨便拿一個Framework 4.5以前的組件去研究,大多數都是這種方式。

這種方式的實現大體是這個樣子:

class?MyClass {void?ActionAsync(para?...);event?ActionCompletedEventHandler?action_completed; }

這種方式使用多線程,所以,它具有多線程的全部特點和要求。

從微軟的建議來看,Framework 4.5以后,并不推薦使用這種模式。

3. 基于任務的異步模型

這種異步模型從Framework 4.0以后引入,使用單一方法來表示異步的開始和完成。這是目前推薦的異步開發方式。在上個文章中的異步模式,就是這個方式。

這個方式的代碼實現是這樣的:

class?MyClass {Task<T>?ActionAsync(para?...); }

?

我們所說的異步,包括前文講的異步,全部是基于這個基于任務的異步模型來討論。

在這個模型下,前文說過,異步不是多線程。今天再強調一遍,異步不僅不是多線程,同時異步也不一定會使用多線程。

二、異步模型中的“任務”

先來看看任務:Task和Task<T>,這是異步模型的核心。

這個“任務”,是一種“承諾”,承諾會在稍后完成任務。

它有兩個關鍵字:async和await。注意:是await,不是wait。這兒再強調一下,Task.Wait是個同步方法,用在多線程中等待。Task是Thread的子集,因此繼承了Wait方法,但這個方法不是給異步用的。

在某些情況下,異步可以采用多線程來實現,這時候,Task.Wait可以用,但這是以多線程的身份來使用的,用出問題要查線程,而不是異步。

關于異步中Task和async、await配合的部分,可以去看前一個文章。地址在:一文說通C#中的異步編程,這兒不再說了。

三、異步編程的兩種模式

1. 單線程模式

先看代碼:

Task<string>?GetHtmlAsync() {var?client?=?new?HttpClient();var?gettask?=?client.GetStringAsync("https://home.cnblogs.com/u/tiger-wang");return?await?gettask; }

這種模式下,這個異步工作于單線程狀態。代碼雖然返回一個任務Task<T>,在這個任務依然在主線程中,并沒有生成一個新的線程。換句話說,這種方式不額外占用線程池資源,也不需要考慮多線程開發中線程鎖定、數據一致性等問題

因為線程沒有切換,所以也不存在上下文切換的問題

2. 多線程模式

既然Task派生自Thread,當然也可以用多線程來實現異步。

看代碼:

Task<string>?GetHtmlAsync() {var?gettask?=?Task.Run(()?=>?{var?client?=?new?HttpClient();return?client.GetStringAsync("https://home.cnblogs.com/u/tiger-wang");});return?await?gettask; }

對方上一段代碼,把調用client.GetStringAsync的部分放到了Task.Run里。

這種方式中,異步被放到了主線程以外的新線程中執行,換句話說,這個異步在以多線程的方式執行。

在這種模式下,async和await的配合,以及對程序執行次序的控制,跟單線程模式是完全一樣的。但是要注意,前邊說了,async和await是異步的關鍵字,它不管多線程的事,也不會為多線程提供任何保護。多線程中的并發鎖、數據鎖、上下文切換,還需要以多線程的方式另外搞定。Task.Run的內部代碼會占用線程池資源,并在一個可用的線程上與主線程并行運行。

四、異步的兩個額外狀態

1. 取消

異步針對的是需要消耗長時間運行的工作。在工作過程中,如果需要,我們可以取消異步的運行。系統提供了一個類CancellationToken來處理這個工作。

定義方式:

Task<T>?ActionAsync(para?...,?CancellationToken?cancellationtoken);

調用方式:

CancellationTokenSource?source?=?new?CancellationTokenSource(); CancellationToken?cancel_token?=?source.Token;await?ActionAsync(para,?cancel_token);

需要取消時:

source.Cancel();

就可以了。

在做API時,異步中加個CancellationToken,是基本的代碼禮節。

2. 進度

長時間運行,如果能給出個進度也不錯。

定義方式:

Task<T>?ActionAsync(para?...,?IProgress<T>?progress);

其中,T是需要返回的進度值,可以是各種需要的類型。

當然,我們需要實現IProgress:

public?class?Progress<T>?:?IProgress<T>?? {??public?Progress();??public?Progress(Action<T>?handler);??protected?virtual?void?OnReport(T?value);??public?event?EventHandler<T>?ProgressChanged;?? }??

IProgress<T>通過回調來發送進度值,引發捕獲并處理。

?

全文完。

?

這篇文章是對前一篇文章的補充和擴展。所以,要兩篇一起看,才更好。

一文說通C#中的異步編程

喜歡就來個三連,讓更多人因你而受益

總結

以上是生活随笔為你收集整理的一文说通C#中的异步编程补遗的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。