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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > C# >内容正文

C#

如何使用 C# 中的 ValueTask

發(fā)布時(shí)間:2023/12/4 C# 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何使用 C# 中的 ValueTask 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在 C# 中利用?ValueTask?避免從異步方法返回?Task?對(duì)象時(shí)分配

翻譯自 Joydip Kanjilal 2020年7月6日 的文章?《How to use ValueTask in C#》(https://www.infoworld.com/article/3565433/how-to-use-valuetask-in-csharp.html)

異步編程已經(jīng)使用了相當(dāng)長(zhǎng)一段時(shí)間了。近年來(lái),隨著?async?和?await?關(guān)鍵字的引入,它變得更加強(qiáng)大。您可以利用異步編程來(lái)提高應(yīng)用程序的響應(yīng)能力和吞吐量。

C# 中異步方法的推薦返回類型是?Task。如果您想編寫(xiě)一個(gè)有返回值的異步方法,那么應(yīng)該返回?Task<T>; 如果想編寫(xiě)事件處理程序,則可以返回?void。在 C# 7.0 之前,異步方法可以返回?Task、Task<T>?或?void。從 C# 7.0 開(kāi)始,異步方法還可以返回?ValueTask(作為?System.Threading.Tasks.Extensions?包的一部分可用)或?ValueTask<T>。本文就討論一下如何在 C# 中使用?ValueTask。

要使用本文提供的代碼示例,您的系統(tǒng)中需要安裝 Visual Studio 2019。如果還沒(méi)有安裝,您可以在這里下載 Visual Studio 2019(https://visualstudio.microsoft.com/downloads/)。

在 Visual Studio 中創(chuàng)建一個(gè) .NET Core 控制臺(tái)應(yīng)用程序項(xiàng)目

首先,讓我們?cè)?Visual Studio 中創(chuàng)建一個(gè) .NET Core 控制臺(tái)應(yīng)用程序項(xiàng)目。假設(shè)您的系統(tǒng)中安裝了 Visual Studio 2019,請(qǐng)按照下面描述的步驟在 Visual Studio 中創(chuàng)建一個(gè)新的 .NET Core 控制臺(tái)應(yīng)用程序項(xiàng)目。

  • 啟動(dòng) Visual Studio IDE。

  • 點(diǎn)擊 “創(chuàng)建新項(xiàng)目”。

  • 在 “創(chuàng)建新項(xiàng)目” 窗口中,從顯示的模板列表中選擇 “控制臺(tái)應(yīng)用(.NET Core)”。

  • 點(diǎn)擊 “下一步”。

  • 在接下來(lái)顯示的 “配置新項(xiàng)目” 窗口,指定新項(xiàng)目的名稱和位置。

  • 點(diǎn)擊 “創(chuàng)建”。

  • 這將在 Visual Studio 2019 中創(chuàng)建一個(gè)新的 .NET Core 控制臺(tái)應(yīng)用程序項(xiàng)目。我們將在本文后面的部分中使用這個(gè)項(xiàng)目來(lái)說(shuō)明?ValueTask?的用法。

    為什么要使用 ValueTask ?

    Task?表示某個(gè)操作的狀態(tài),即此操作是否完成、取消等。異步方法可以返回?Task?或者?ValueTask。

    現(xiàn)在,由于?Task?是一個(gè)引用類型,從異步方法返回一個(gè)?Task?對(duì)象意味著每次調(diào)用該方法時(shí)都會(huì)在托管堆(managed heap)上分配該對(duì)象。因此,在使用?Task?時(shí)需要注意的一點(diǎn)是,每次從方法返回?Task?對(duì)象時(shí)都需要在托管堆中分配內(nèi)存。如果你的方法執(zhí)行的操作的結(jié)果立即可用或同步完成,則不需要這種分配,因此代價(jià)很高。

    這正是?ValueTask?要出手相助的目的,ValueTask<T>?提供了兩個(gè)主要好處。首先,ValueTask<T>?提高了性能,因?yàn)樗恍枰诙?#xff08;heap)中分配; 其次,它的實(shí)現(xiàn)既簡(jiǎn)單又靈活。當(dāng)結(jié)果立即可用時(shí),通過(guò)從異步方法返回?ValueTask<T>?代替?Task<T>,你可以避免不必要的分配開(kāi)銷(xiāo),因?yàn)檫@里的 “T” 表示一個(gè)結(jié)構(gòu),而 C# 中的結(jié)構(gòu)體(struct)是一個(gè)值類型(與?Task<T>?中表示類的 “T” 不同)。

    C# 中?Task?和?ValueTask?表示兩種主要的 “可等待(awaitable)” 類型。請(qǐng)注意,您不能阻塞(block)一個(gè)?ValueTask。如果需要阻塞,則應(yīng)使用?AsTask?方法將?ValueTask?轉(zhuǎn)換為?Task,然后在該引用?Task?對(duì)象上進(jìn)行阻塞。

    另外請(qǐng)注意,每個(gè)?ValueTask?只能被消費(fèi)(consumed)一次。這里的單詞 “消費(fèi)(consume)”?是指?ValueTask?可以異步等待(await)操作完成,或者利用?AsTask?將?ValueTask?轉(zhuǎn)換為?Task。但是,ValueTask?只應(yīng)被消費(fèi)(consumed)一次,之后?ValueTask<T>?應(yīng)被忽略。

    C# 中的 ValueTask 示例

    假設(shè)有一個(gè)異步方法返回一個(gè)?Task。你可以利用?Task.FromResult?創(chuàng)建?Task?對(duì)象,如下面給出的代碼片段所示。

    public Task<int> GetCustomerIdAsync() {return Task.FromResult(1); }

    上面的代碼片段并沒(méi)有創(chuàng)建整個(gè)異步狀態(tài)機(jī)制,但它在托管堆(managed heap)中分配了一個(gè)?Task?對(duì)象。為了避免這種分配,您可能希望利用?ValueTask?代替,像下面給出的代碼片段所示的那樣。

    public ValueTask<int> GetCustomerIdAsync() {return new ValueTask<int>(1); }

    下面的代碼片段演示了?ValueTask?的同步實(shí)現(xiàn)。

    public interface IRepository<T> {ValueTask<T> GetData(); }

    Repository?類擴(kuò)展了?IRepository?接口,并實(shí)現(xiàn)了如下所示的方法。

    public class Repository<T> : IRepository<T> {public ValueTask<T> GetData(){var value = default(T);return new ValueTask<T>(value);} }

    下面是如何從?Main?方法調(diào)用?GetData?方法。

    static void Main(string[] args) {IRepository<int> repository = new Repository<int>();var result = repository.GetData();if (result.IsCompleted)Console.WriteLine("Operation complete...");elseConsole.WriteLine("Operation incomplete...");Console.ReadKey(); }

    現(xiàn)在讓我們將另一個(gè)方法添加到我們的存儲(chǔ)庫(kù)(repository)中,這次是一個(gè)名為?GetDataAsync?的異步方法。以下是修改后的?IRepository?接口的樣子。

    public interface IRepository<T> {ValueTask<T> GetData();ValueTask<T> GetDataAsync(); }

    GetDataAsync?方法由?Repository?類實(shí)現(xiàn),如下面給出的代碼片段所示。

    public class Repository<T> : IRepository<T> {public ValueTask<T> GetData(){var value = default(T);return new ValueTask<T>(value);}public async ValueTask<T> GetDataAsync(){var value = default(T);await Task.Delay(100);return value;} }


    C# 中應(yīng)該在什么時(shí)候使用 ValueTask ?

    盡管?ValueTask?提供了一些好處,但是使用?ValueTask?代替?Task?有一定的權(quán)衡。ValueTask?是具有兩個(gè)字段的值類型,而?Task?是具有單個(gè)字段的引用類型。因此,使用?ValueTask?意味著要處理更多的數(shù)據(jù),因?yàn)榉椒ㄕ{(diào)用將返回兩個(gè)數(shù)據(jù)字段而不是一個(gè)。另外,如果您等待(await)一個(gè)返回?ValueTask?的方法,那么該異步方法的狀態(tài)機(jī)也會(huì)更大,因?yàn)樗仨毴菁{一個(gè)包含兩個(gè)字段的結(jié)構(gòu)體而不是在使用?Task?時(shí)的單個(gè)引用。

    此外,如果異步方法的使用者使用?Task.WhenAll?或者?Task.WhenAny,在異步方法中使用?ValueTask<T>?作為返回類型可能會(huì)代價(jià)很高。這是因?yàn)槟枰褂?AsTask?方法將?ValueTask<T>?轉(zhuǎn)換為?Task<T>,這會(huì)引發(fā)一個(gè)分配,而如果使用起初緩存的?Task<T>,則可以輕松避免這種分配。

    經(jīng)驗(yàn)法則是這樣的:當(dāng)您有一段代碼總是異步的時(shí),即當(dāng)操作(總是)不能立即完成時(shí),請(qǐng)使用?Task。當(dāng)異步操作的結(jié)果已經(jīng)可用時(shí),或者當(dāng)您已經(jīng)緩存了結(jié)果時(shí),請(qǐng)利用?ValueTask。不管怎樣,在考慮使用?ValueTask?之前,您都應(yīng)該執(zhí)行必要的性能分析。

    ValueTask?是?readonly struct?類型,Task?是?class?類型。
    相關(guān)鏈接:C# 中 Struct 和 Class 的區(qū)別總結(jié)。

    作者 :Joydip Kanjilal?
    譯者 :技術(shù)譯民
    出品 :技術(shù)譯站(https://ITTranslator.cn/)

    總結(jié)

    以上是生活随笔為你收集整理的如何使用 C# 中的 ValueTask的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。