国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

實(shí)現(xiàn)基于Task的異步模式

2019-11-14 13:54:00
字體:
供稿:網(wǎng)友

返回該系列目錄《基于Task的異步模式--全面介紹》

生成方法

編譯器生成

在.NET Framework 4.5中,C#編譯器實(shí)現(xiàn)了TAP。任何標(biāo)有async關(guān)鍵字的方法都是異步方法,編譯器會(huì)使用TAP執(zhí)行必要的轉(zhuǎn)換從而異步地實(shí)現(xiàn)方法。這樣的方法應(yīng)該返回Task或者Task<TResult>類型。在后者的案例中,方法體應(yīng)該返回一個(gè)TResult,且編譯器將確保通過返回的Task<TResult>是可利用的。相似地,方法體內(nèi)未經(jīng)處理的異常會(huì)被封送到輸出的task,造成返回的Task以Faulted的狀態(tài)結(jié)束。一個(gè)例外是如果OperationCanceledException(或派生類型)未經(jīng)處理,那么返回的Task會(huì)以Canceled狀態(tài)結(jié)束。

手動(dòng)生成

開發(fā)者可以手動(dòng)地實(shí)現(xiàn)TAP,就像編譯器那樣或者更好地控制方法的實(shí)現(xiàn)。編譯器依賴來自System.Threading.Tasks命名空間暴露的公開表面區(qū)域(和建立在System.Threading.Tasks之上的System.Runtime.CompilerServices中支持的類型),還有對(duì)開發(fā)者直接可用的功能。當(dāng)手動(dòng)實(shí)現(xiàn)TAP方法時(shí),開發(fā)者必須保證當(dāng)異步操作完成時(shí),完成返回的Task。

混合生成

在編譯器生成的實(shí)現(xiàn)中混合核心邏輯的實(shí)現(xiàn),對(duì)于手動(dòng)實(shí)現(xiàn)TAP通常是很有用的。比如這種情況,為了避免方法直接調(diào)用者產(chǎn)生而不是通過Task暴露的異常,如:

public Task<int> MethodAsync(string input){    if (input == null) throw new ArgumentNullException("input");    return MethodAsyncInternal(input);}PRivate async Task<int> MethodAsyncInternal(string input){    … // code that uses await}

參數(shù)應(yīng)該在編譯器生成的異步方法之外改變,這種委托有用的另一種場(chǎng)合是,當(dāng)一個(gè)“快速通道”優(yōu)化可以通過返回一個(gè)緩存的task來實(shí)現(xiàn)的時(shí)候。

工作負(fù)荷

計(jì)算受限和I/O受限的異步操作可以通過TAP方法實(shí)現(xiàn)。然而,當(dāng)TAP的實(shí)現(xiàn)從一個(gè)庫公開暴露時(shí),應(yīng)該只提供給包含I/O操作的工作負(fù)荷(它們也可以包含計(jì)算,但不應(yīng)該只包含計(jì)算)。如果一個(gè)方法純粹受計(jì)算限制,它應(yīng)該只通過一個(gè)異步實(shí)現(xiàn)暴露,消費(fèi)者然后就可以為了把該任務(wù)卸載給其他的線程的目的來選擇是否把那個(gè)同步方法的調(diào)用包裝成一個(gè)Task,并且/或者來實(shí)現(xiàn)并行。

計(jì)算限制

Task類最適合表示計(jì)算密集型操作。默認(rèn)地,為了提供有效的執(zhí)行操作,它利用了.Net線程池中特殊的支持,同時(shí)也對(duì)異步計(jì)算何時(shí),何地,如何執(zhí)行提供了大量的控制。

生成計(jì)算受限的tasks有幾種方法。

  1. 在.Net 4中,啟動(dòng)一個(gè)新的計(jì)算受限的task的主要方法是TaskFactory.StartNew(),該方法接受一個(gè)異步執(zhí)行的委托(一般來說是一個(gè)Action或者一個(gè)Func<TResult>)。如果提供了一個(gè)Action,返回的Task就代表那個(gè)委托的異步執(zhí)行操作。如果提供了一個(gè)Func<TResult>,就會(huì)返回一個(gè)Task<TResult>。存在StartNew()的重載,該重載接受CancellationToken,TaskCreationOptions,和TaskScheduler,這些都對(duì)task的調(diào)度和執(zhí)行提供了細(xì)粒度的控制。作用在當(dāng)前調(diào)度者的工廠實(shí)例可以作為Task類的靜態(tài)屬性,例如Task.Factory.StartNew()。
  2. 在.Net 4.5中,Task類型暴露了一個(gè)靜態(tài)的Run方法作為一個(gè)StartNew方法的捷徑,可以很輕松地使用它來啟動(dòng)一個(gè)作用在線程池上的計(jì)算受限的task。從.Net 4.5開始,對(duì)于啟動(dòng)一個(gè)計(jì)算受限的task,這是一個(gè)更受人喜歡的機(jī)制。當(dāng)行為要求更多的細(xì)粒度控制時(shí),才直接使用StartNew。
  3. Task類型公開了構(gòu)造函數(shù)和Start方法。如果必須要有分離自調(diào)度的構(gòu)造函數(shù),這些就是可以使用的(正如先前提到的,公開的APIs必須只返回已經(jīng)啟動(dòng)的tasks)。
  4. Task類型公開了多個(gè)ContinueWith的重載。當(dāng)另外一個(gè)task完成的時(shí)候,該方法會(huì)創(chuàng)建新的將被調(diào)度的task。該重載接受CancellationToken,TaskCreationOptions,和TaskScheduler,這些都對(duì)task的調(diào)度和執(zhí)行提供了細(xì)粒度的控制。
  5. TaskFactory類提供了ContinueWhenAll 和ContinueWhenAny方法。當(dāng)提供的一系列的tasks中的所有或任何一個(gè)完成時(shí),這些方法會(huì)創(chuàng)建一個(gè)即將被調(diào)度的新的task。有了ContinueWith,就有了對(duì)于調(diào)度的控制和任務(wù)的執(zhí)行的支持。

思考下面的渲染圖片的異步方法。task體可以獲得cancellation token為的是,當(dāng)渲染發(fā)生的時(shí)候,如果一個(gè)撤銷請(qǐng)求到達(dá)后,代碼可能過早退出。而且,如果一個(gè)撤銷請(qǐng)求在渲染開始之前發(fā)生,我們也可以阻止任何的渲染。

public Task<Bitmap> RenderAsync(    ImageData data, CancellationToken cancellationToken){    return Task.Run(() =>    {        var bmp = new Bitmap(data.Width, data.Height);        for(int y=0; y<data.Height; y++)        {            cancellationToken.ThrowIfCancellationRequested();            for(int x=0; x<data.Width; x++)            {                … // render pixel [x,y] into bmp            }        }        return bmp;    }, cancellationToken);}

如果下面的條件至少一個(gè)是正確的,計(jì)算受限的tasks會(huì)以一個(gè)Canceled狀態(tài)的結(jié)束:

  1. 在Task過度到TaskStatus.Running狀態(tài)之前,CancellationToken為一個(gè)發(fā)出撤銷請(qǐng)求的創(chuàng)建方法的參數(shù)提供(如StartNew,Run)。
  2. 有這樣的一個(gè)Task,它內(nèi)部有未處理的OperationCanceledException。該OperationCanceledException 包含和CancellationToken屬性同名的CancellationToken傳遞到該Task,且該CancellationToken已經(jīng)發(fā)出了撤銷請(qǐng)求。

如果該Task體中有另外一個(gè)未經(jīng)處理的異常,那么該Task就會(huì)以Faulted的狀態(tài)結(jié)束,同時(shí)在該task上等待的任何嘗試或者訪問它的結(jié)果都將導(dǎo)致拋出異常。

I/O限制

使用TaskCompletionSource<TResult>類型創(chuàng)建的Tasks不應(yīng)該直接被全部執(zhí)行的線程返回。TaskCompletionSource<TResult>暴露了一個(gè)返回相關(guān)的Task<TResult>實(shí)例的Task屬性。該task的生命周期通過TaskCompletionSource<TResult>實(shí)例暴露的方法控制,換句話說,這些實(shí)例包括SetResult, SetException, SetCanceled, 和它們的TrySet* 變量。

思考這樣的需求,創(chuàng)建一個(gè)在特定的時(shí)間之后會(huì)完成的task。比如,當(dāng)開發(fā)者在UI場(chǎng)景中想要延遲一個(gè)活動(dòng)一段時(shí)間時(shí),這可能使有用的。.NET中的System.Threading.Timer類已經(jīng)提供了這種能力,在一段特定時(shí)間后異步地調(diào)用一個(gè)委托,并且我們可以使用TaskCompletionSource<TResult>把一個(gè)Task放在timer上,例如:

public static Task<DateTimeOffset> Delay(int millisecondsTimeout){    var tcs = new TaskCompletionSource<DateTimeOffset>();    new Timer(self =>    {        ((IDisposable)self).Dispose();        tcs.TrySetResult(DateTimeOffset.UtcNow);    }).Change(millisecondsTimeout, -1);    return tcs.Task;}

在.Net 4.5中,Task.Delay()就是為了這個(gè)目的而生的。比如,這樣的一個(gè)方法可以使用到另一個(gè)異步方法的內(nèi)部,以實(shí)現(xiàn)一個(gè)異步的輪訓(xùn)循環(huán):

public static async Task Poll(    Uri url,     CancellationToken cancellationToken,     iprogress<bool> progress){    while(true)    {        await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken);        bool success = false;        try        {            await DownloadStringAsync(url);            success = true;        }        catch { /* ignore errors */ }        progress.Report(success);    }}

沒有TaskCompletionSource<TResult>的非泛型副本。然而,Task<TResult>派生自Task,因而,泛型的TaskCompletionSource<TResult>可以用于那些 I/O受限的方法,它們都利用一個(gè)假的TResult源(Boolean是默認(rèn)選擇,如果開發(fā)者關(guān)心Task向下轉(zhuǎn)型的Task<TResult>的消費(fèi)者,那么可以使用一個(gè)私有的TResult類型)僅僅返回一個(gè)Task。比如,開發(fā)的之前的Delay方法是為了順著產(chǎn)生的Task<DateTimeOffset>返回當(dāng)前的時(shí)間。如果這樣的 一個(gè)結(jié)果值是不必要的,那么該方法可以通過下面的代碼取而代之(注意返回類型的改變和TrySetresult參數(shù)的改變):

public static Task Delay(int millisecondsTimeout){    var tcs = new TaskCompletionSource<bool>();    new Timer(self =>    {        ((IDisposable)self).Dispose();        tcs.TrySetResult(true);    }).Change(millisecondsTimeout, -1);    return tcs.Task;}

混合計(jì)算限制和I/O限制的任務(wù)

異步方法不是僅僅受限于計(jì)算受限或者I/O受限的操作,而是可以代表這兩者的混合。實(shí)際上,通常情況是不同性質(zhì)的多個(gè)異步操作被組合在一起生成更大的混合操作。比如,思考之前的RenderAsync方法,該方法基于一些輸入的ImageData執(zhí)行一個(gè)計(jì)算密集的操作來渲染一張圖片。該ImageData可能來自于一個(gè)我們異步訪問的Web服務(wù):

public async Task<Bitmap> DownloadDataAndRenderImageAsync(    CancellationToken cancellationToken){    var imageData = await DownloadImageDataAsync(cancellationToken);    return await RenderAsync(imageData, cancellationToken);}

這個(gè)例子也展示了一個(gè)單獨(dú)的CancellationToken是如何通過多個(gè)異步操作被線程化的。

返回該系列目錄《基于Task的異步模式--全面介紹》



發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 宁武县| 寿光市| 彭山县| 盐津县| 财经| 大田县| 东台市| 吉林省| 武山县| 南靖县| 临沭县| 湄潭县| 盐亭县| 开封市| 台安县| 密山市| 临泽县| 昌邑市| 武乡县| 白城市| 始兴县| 临朐县| 黑山县| 南通市| 哈巴河县| 双峰县| 铜川市| 安顺市| 尚志市| 南安市| 湟源县| 宁津县| 威远县| 韩城市| 新民市| 璧山县| 博兴县| 霍山县| 杭锦后旗| 建昌县| 临颍县|