Programování

Jak používat ValueTask v C #

Asynchronní programování se používá už nějakou dobu. V posledních letech byla vylepšena zavedením asynchronních a čekajících klíčových slov. Asynchronní programování můžete využít ke zvýšení odezvy a propustnosti vaší aplikace.

Doporučený návratový typ asynchronní metody v C # je Task. Pokud byste chtěli napsat asynchronní metodu, která vrací hodnotu, měli byste Task vrátit. Pokud byste chtěli napsat obslužnou rutinu události, můžete místo toho vrátit neplatnost. Až do C # 7.0 mohla asynchronní metoda vrátit Task, Task nebo void. Počínaje C # 7.0 může asynchronní metoda také vrátit ValueTask (k dispozici jako součást balíčku System.Threading.Tasks.Extensions) nebo ValueTask. Tento článek představuje diskusi o tom, jak můžeme pracovat s ValueTask v C #.

Chcete-li pracovat s příklady kódu uvedenými v tomto článku, měli byste mít ve svém systému nainstalovanou Visual Studio 2019. Pokud ještě nemáte kopii, můžete si stáhnout Visual Studio 2019 zde.

Vytvořte projekt aplikace konzoly .NET Core v sadě Visual Studio

Nejprve si vytvořme projekt konzolové aplikace .NET Core v sadě Visual Studio. Za předpokladu, že je ve vašem systému nainstalovaná sada Visual Studio 2019, postupujte podle níže uvedených kroků a vytvořte nový projekt konzolové aplikace .NET Core v sadě Visual Studio.

  1. Spusťte Visual Studio IDE.
  2. Klikněte na „Vytvořit nový projekt“.
  3. V okně „Vytvořit nový projekt“ vyberte ze zobrazeného seznamu šablon „Console App (.NET Core)“.
  4. Klikněte na Další.
  5. V dalším okně „Konfigurace nového projektu“ zadejte název a umístění nového projektu.
  6. Klikněte na Vytvořit.

Tím se vytvoří nový projekt aplikace konzoly .NET Core v sadě Visual Studio 2019. Tento projekt použijeme k ilustraci použití ValueTask v následujících částech tohoto článku.

Proč bych měl používat ValueTask?

Úkol představuje stav nějaké operace, tj. Zda je operace dokončena, zrušena atd. Asynchronní metoda může vrátit Task nebo ValueTask.

Nyní, protože Task je referenční typ, vrácení Task objektu z asynchronní metody znamená přidělení objektu na spravované haldě při každém volání metody. Jedno upozornění při používání Task je tedy v tom, že musíte alokovat paměť ve spravované haldě pokaždé, když vrátíte Task objekt z vaší metody. Pokud je výsledek operace prováděné vaší metodou k dispozici okamžitě nebo se provádí synchronně, není toto přidělení nutné a proto se stává nákladným.

Tady přesně přijde na záchranu ValueTask. ValueTask poskytuje dvě hlavní výhody. Za prvé, ValueTask zlepšuje výkon, protože nepotřebuje přidělení haldy, a za druhé, jeho implementace je snadná a flexibilní. Když vracíte ValueTask místo Task z asynchronní metody, když je výsledek okamžitě k dispozici, můžete se vyhnout zbytečné režii alokace, protože „T“ zde představuje strukturu a struktura v C # je typ hodnoty (na rozdíl od „T“ v Task, což představuje třídu).

Task a ValueTask představují dva primární „očekávané“ typy v C #. Upozorňujeme, že na ValueTask nelze blokovat. Pokud potřebujete blokovat, měli byste ValueTask převést na Task pomocí metody AsTask a poté zablokovat na tomto referenčním Task objektu.

Také si všimněte, že každý ValueTask může být spotřebován pouze jednou. Zde slovo „konzumovat“ znamená, že ValueTask může asynchronně čekat na dokončení operace (nebo ji čekat) nebo využít AsTask k převodu ValueTask na úkol. ValueTask by však měl být spotřebován pouze jednou, po kterém by měl být ValueTask ignorován.

Příklad ValueTask v C #

Předpokládejme, že máte asynchronní metodu, která vrací Task. Mohli byste využít Task.FromResult k vytvoření Task objektu, jak je ukázáno v níže uvedeném fragmentu kódu.

veřejná úloha GetCustomerIdAsync ()

{

vrátit Task.FromResult (1);

}

Výše uvedený fragment kódu nevytváří celou magii stroje asynchronního stavu, ale přiděluje objekt Task ve spravované haldě. Abyste se tomuto přidělení vyhnuli, možná budete chtít místo toho využít výhod ValueTask, jak je ukázáno v níže uvedeném fragmentu kódu.

public ValueTask GetCustomerIdAsync ()

{

vrátit nový ValueTask (1);

}

Následující fragment kódu ilustruje synchronní implementaci ValueTask.

 veřejné rozhraní IRepository

    {

ValueTask GetData ();

    }

Třída Repository rozšiřuje rozhraní IRepository a implementuje jeho metody, jak je znázorněno níže.

  veřejná třída Repository: IRepository

    {

veřejný ValueTask GetData ()

        {

var hodnota = výchozí (T);

vrátit nový ValueTask (hodnota);

        }

    }

Zde je způsob, jakým můžete volat metodu GetData z metody Main.

static void Main (řetězec [] args)

        {

IRepository repository = new Repository ();

var result = repository.GetData ();

if (result.IsCompleted)

Console.WriteLine ("operace dokončena ...");

jiný

Console.WriteLine („Operace neúplná ...“);

Console.ReadKey ();

        }

Nyní přidáme do našeho úložiště další metodu, tentokrát asynchronní metodu s názvem GetDataAsync. Takto by vypadalo upravené rozhraní IRepository.

veřejné rozhraní IRepository

    {

ValueTask GetData ();

ValueTask GetDataAsync ();

    }

Metoda GetDataAsync je implementována Repository třídou, jak je ukázáno ve fragmentu kódu uvedeném níže.

  veřejná třída Repository: IRepository

    {

veřejný ValueTask GetData ()

        {

var hodnota = výchozí (T);

vrátit nový ValueTask (hodnota);

        }

veřejná asynchronní ValueTask GetDataAsync ()

        {

var hodnota = výchozí (T);

čekat na Task.Delay (100);

návratová hodnota;

        }

    }

Kdy mám použít ValueTask v C #?

I když výhody, které ValueTask poskytuje, existují určité kompromisy při používání ValueTask namísto Task. ValueTask je typ hodnoty se dvěma poli, zatímco Task je referenční typ s jediným polem. Proto použití ValueTask znamená pracovat s více daty, protože volání metody by vrátilo dvě pole dat namísto jednoho. Také pokud očekáváte metodu, která vrací ValueTask, stavový stroj pro tuto asynchronní metodu by byl také větší - protože by musel pojmout strukturu, která obsahuje dvě pole namísto jediného odkazu v případě Task.

Dále, pokud spotřebitel asynchronní metody používá Task.WhenAll nebo Task.WhenAny, použití ValueTask jako návratového typu v asynchronní metodě může být nákladné. Je to proto, že byste museli převést ValueTask na Task pomocí metody AsTask, což by vyvolalo přidělení, kterému by se dalo snadno vyhnout, kdyby se na prvním místě použila Task v mezipaměti.

Zde platí pravidlo. Úkol použijte, když máte část kódu, která bude vždy asynchronní, tj. Když operace nebude okamžitě dokončena. Využijte ValueTask, když je již k dispozici výsledek asynchronní operace nebo když již máte výsledek v mezipaměti. V každém případě byste před provedením ValueTask měli provést nezbytnou analýzu výkonu.

Jak udělat více v C #:

  • Jak používat neměnnost v C.
  • Jak používat const, readonly a static v C #
  • Jak používat datové anotace v C #
  • Jak pracovat s identifikátory GUID v C # 8
  • Kdy použít abstraktní třídu vs. rozhraní v C #
  • Jak pracovat s AutoMapperem v C #
  • Jak používat výrazy lambda v C #
  • Jak pracovat s delegáty Action, Func a Predicate v C #
  • Jak pracovat s delegáty v C #
  • Jak implementovat jednoduchý záznamník v C #
  • Jak pracovat s atributy v C #
  • Jak pracovat s log4net v C #
  • Jak implementovat vzor návrhu úložiště v C #
  • Jak pracovat s odrazem v C #
  • Jak pracovat se souborovým systémem v C #
  • Jak provést línou inicializaci v C #
  • Jak pracovat s MSMQ v C #
  • Jak pracovat s metodami rozšíření v C #
  • Jak na nás lambda výrazy v C #
  • Kdy použít volatilní klíčové slovo v C #
  • Jak používat klíčové slovo výnos v C #
  • Jak implementovat polymorfismus v C #
  • Jak vytvořit svůj vlastní plánovač úloh v C #
  • Jak pracovat s RabbitMQ v C #
  • Jak pracovat s n-ticí v C #
  • Zkoumání virtuálních a abstraktních metod v C #
  • Jak používat Dapper ORM v C #
  • Jak používat návrhový vzor muší váhy v C #
$config[zx-auto] not found$config[zx-overlay] not found