<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一文說(shuō)通C#中的異步編程補(bǔ)遺

          共 2930字,需瀏覽 6分鐘

           ·

          2020-08-11 02:15

          前文寫(xiě)了關(guān)于C#中的異步編程。后臺(tái)有無(wú)數(shù)人在討論,很多人把異步和多線程混了。

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

          所以,本文從體系的角度,再寫(xiě)一下這個(gè)異步編程。

          ?

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

          1. 異步編程模型

          這是C#中早期的異步模型,通過(guò)IAsyncResult接口來(lái)實(shí)現(xiàn)。

          實(shí)現(xiàn)的代碼大體是這個(gè)樣子:

          class?MyClass
          {

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

          這種方式在一些庫(kù)里還有保留,像FileSteam類里的BeginReadEndRead方法組,就是這種方式。

          編程時(shí),不建議用這種方式。

          2. 基于事件的異步模型

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

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

          這種方式的實(shí)現(xiàn)大體是這個(gè)樣子:

          class?MyClass
          {

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

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

          從微軟的建議來(lái)看,F(xiàn)ramework 4.5以后,并不推薦使用這種模式。

          3. 基于任務(wù)的異步模型

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

          這個(gè)方式的代碼實(shí)現(xiàn)是這樣的:

          class?MyClass
          {

          ??Task?ActionAsync(para?...);
          }

          ?

          我們所說(shuō)的異步,包括前文講的異步,全部是基于這個(gè)基于任務(wù)的異步模型來(lái)討論。

          在這個(gè)模型下,前文說(shuō)過(guò),異步不是多線程。今天再?gòu)?qiáng)調(diào)一遍,異步不僅不是多線程,同時(shí)異步也不一定會(huì)使用多線程。

          二、異步模型中的“任務(wù)”

          先來(lái)看看任務(wù):TaskTask,這是異步模型的核心。

          這個(gè)“任務(wù)”,是一種“承諾”,承諾會(huì)在稍后完成任務(wù)。

          它有兩個(gè)關(guān)鍵字:asyncawait。注意:是await,不是wait。這兒再?gòu)?qiáng)調(diào)一下,Task.Wait是個(gè)同步方法,用在多線程中等待。TaskThread的子集,因此繼承了Wait方法,但這個(gè)方法不是給異步用的。

          在某些情況下,異步可以采用多線程來(lái)實(shí)現(xiàn),這時(shí)候,Task.Wait可以用,但這是以多線程的身份來(lái)使用的,用出問(wèn)題要查線程,而不是異步。

          關(guān)于異步中Taskasync、await配合的部分,可以去看前一個(gè)文章。地址在:一文說(shuō)通C#中的異步編程,這兒不再說(shuō)了。

          三、異步編程的兩種模式

          1. 單線程模式

          先看代碼:

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

          ??return?await?gettask;
          }

          這種模式下,這個(gè)異步工作于單線程狀態(tài)。代碼雖然返回一個(gè)任務(wù)Task,在這個(gè)任務(wù)依然在主線程中,并沒(méi)有生成一個(gè)新的線程。換句話說(shuō),這種方式不額外占用線程池資源,也不需要考慮多線程開(kāi)發(fā)中線程鎖定、數(shù)據(jù)一致性等問(wèn)題。

          因?yàn)榫€程沒(méi)有切換,所以也不存在上下文切換的問(wèn)題。

          2. 多線程模式

          既然Task派生自Thread,當(dāng)然也可以用多線程來(lái)實(shí)現(xiàn)異步。

          看代碼:

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

          ??return?await?gettask;
          }

          對(duì)方上一段代碼,把調(diào)用client.GetStringAsync的部分放到了Task.Run里。

          這種方式中,異步被放到了主線程以外的新線程中執(zhí)行,換句話說(shuō),這個(gè)異步在以多線程的方式執(zhí)行。

          在這種模式下,asyncawait的配合,以及對(duì)程序執(zhí)行次序的控制,跟單線程模式是完全一樣的。但是要注意,前邊說(shuō)了,asyncawait是異步的關(guān)鍵字,它不管多線程的事,也不會(huì)為多線程提供任何保護(hù)。多線程中的并發(fā)鎖、數(shù)據(jù)鎖、上下文切換,還需要以多線程的方式另外搞定。Task.Run的內(nèi)部代碼會(huì)占用線程池資源,并在一個(gè)可用的線程上與主線程并行運(yùn)行。

          四、異步的兩個(gè)額外狀態(tài)

          1. 取消

          異步針對(duì)的是需要消耗長(zhǎng)時(shí)間運(yùn)行的工作。在工作過(guò)程中,如果需要,我們可以取消異步的運(yùn)行。系統(tǒng)提供了一個(gè)類CancellationToken來(lái)處理這個(gè)工作。

          定義方式:

          Task?ActionAsync(para?...,?CancellationToken?cancellationtoken);

          調(diào)用方式:

          CancellationTokenSource?source?=?new?CancellationTokenSource();
          CancellationToken?cancel_token?=?source.Token;

          await?ActionAsync(para,?cancel_token);

          需要取消時(shí):

          source.Cancel();

          就可以了。

          在做API時(shí),異步中加個(gè)CancellationToken,是基本的代碼禮節(jié)。

          2. 進(jìn)度

          長(zhǎng)時(shí)間運(yùn)行,如果能給出個(gè)進(jìn)度也不錯(cuò)。

          定義方式:

          Task?ActionAsync(para?...,?IProgress?progress);

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

          當(dāng)然,我們需要實(shí)現(xiàn)IProgress

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

          IProgress通過(guò)回調(diào)來(lái)發(fā)送進(jìn)度值,引發(fā)捕獲并處理。

          ?

          全文完。

          ?

          這篇文章是對(duì)前一篇文章的補(bǔ)充和擴(kuò)展。所以,要兩篇一起看,才更好。

          一文說(shuō)通C#中的異步編程

          喜歡就來(lái)個(gè)三連,讓更多人因你而受益

          瀏覽 26
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中国操逼电影 | 五月婷婷亚洲综合网 | 大香蕉在线啪啪 | 激情1234 | 99在线观看欧美 |