Programmering

Sådan bruges ValueTask i C #

Asynkron programmering har været i brug i nogen tid nu. I de senere år er det blevet gjort mere kraftfuldt med introduktionen af ​​asynkroniserings- og afventer nøgleord. Du kan drage fordel af asynkron programmering for at øge din applikations lydhørhed og kapacitet.

Den anbefalede returtype for en asynkron metode i C # er Task. Du skal returnere Task, hvis du vil skrive en asynkron metode, der returnerer en værdi. Hvis du vil skrive en begivenhedshåndterer, kan du i stedet returnere ugyldigt. Indtil C # 7.0 kunne en asynkron metode returnere Task, Task eller ugyldig. Begyndende med C # 7.0 kan en asynkron metode også returnere ValueTask (tilgængelig som en del af System.Threading.Tasks.Extensions-pakken) eller ValueTask. Denne artikel præsenterer en diskussion af, hvordan vi kan arbejde med ValueTask i C #.

For at arbejde med kodeeksemplerne i denne artikel skal du have Visual Studio 2019 installeret i dit system. Hvis du ikke allerede har en kopi, kan du downloade Visual Studio 2019 her.

Opret et .NET Core-konsolapplikationsprojekt i Visual Studio

Lad os først oprette et .NET Core-konsolapplikationsprojekt i Visual Studio. Forudsat at Visual Studio 2019 er installeret i dit system, skal du følge nedenstående trin for at oprette et nyt .NET Core-konsolapplikationsprojekt i Visual Studio.

  1. Start Visual Studio IDE.
  2. Klik på "Opret nyt projekt."
  3. I vinduet "Opret nyt projekt" skal du vælge "Konsolapp (.NET Core)" fra listen over skabeloner, der vises.
  4. Klik på Næste.
  5. I vinduet "Konfigurer dit nye projekt", der vises nedenfor, skal du angive navnet og placeringen for det nye projekt.
  6. Klik på Opret.

Dette opretter et nyt .NET Core-konsolapplikationsprojekt i Visual Studio 2019. Vi bruger dette projekt til at illustrere brugen af ​​ValueTask i de efterfølgende afsnit i denne artikel.

Hvorfor skal jeg bruge ValueTask?

En opgave repræsenterer tilstanden for en eller anden operation, dvs. om operationen er afsluttet, annulleret osv. En asynkron metode kan returnere enten en opgave eller en værdiopgave.

Nu, da opgave er en referencetype, betyder det, at returnering af et opgaveobjekt fra en asynkron metode tildeler objektet på den administrerede bunke hver gang metoden kaldes. Således er en advarsel ved brug af opgave, at du skal allokere hukommelse i den administrerede bunke, hver gang du returnerer et opgaveobjekt fra din metode. Hvis resultatet af den operation, der udføres efter din metode, er tilgængelig med det samme eller fuldføres synkront, er denne allokering ikke nødvendig og bliver derfor dyr.

Her er nøjagtigt hvor ValueTask kommer til undsætning. ValueTask giver to store fordele. For det første forbedrer ValueTask ydeevnen, fordi den ikke har brug for bunktildeling, og for det andet er den både let og fleksibel at implementere. Ved at returnere ValueTask i stedet for Task fra en asynkron metode, når resultatet er umiddelbart tilgængeligt, kan du undgå den unødvendige allokeringsomkostning, da "T" her repræsenterer en struktur, og en struct i C # er en værditype (i modsætning til "T" i Task, som repræsenterer en klasse).

Task og ValueTask repræsenterer to primære "ventelige" typer i C #. Bemærk, at du ikke kan blokere for en ValueTask. Hvis du har brug for at blokere, skal du konvertere ValueTask til en opgave ved hjælp af AsTask-metoden og derefter blokere for dette referenceopgaveobjekt.

Bemærk også, at hver ValueTask kun kan forbruges en gang. Her betyder ordet "forbruge", at en ValueTask kan asynkront vente på (afventer) operationen for at fuldføre eller drage fordel af AsTask til at konvertere en ValueTask til en Task. En ValueTask bør dog kun forbruges en gang, hvorefter ValueTask skal ignoreres.

ValueTask-eksempel i C #

Antag at du har en asynkron metode, der returnerer en opgave. Du kan muligvis drage fordel af Task.FromResult for at oprette opgaveobjektet som vist i kodeuddraget nedenfor.

offentlig opgave GetCustomerIdAsync ()

{

returner Task.FromResult (1);

}

Ovenstående kodestykke opretter ikke hele maskinens magi for async, men det tildeler et opgaveobjekt i den administrerede bunke. For at undgå denne allokering vil du måske i stedet drage fordel af en ValueTask som vist i kodestykket nedenfor.

offentlig ValueTask GetCustomerIdAsync ()

{

returner ny ValueTask (1);

}

Følgende kodestykke illustrerer en synkron implementering af ValueTask.

 offentlig grænseflade IR-depot

    {

ValueTask GetData ();

    }

Repository-klassen udvider IRepository-grænsefladen og implementerer dens metoder som vist nedenfor.

  public class Repository: IRepository

    {

offentlig ValueTask GetData ()

        {

var værdi = standard (T);

returner ny ValueTask (værdi);

        }

    }

Her er hvordan du kan kalde GetData-metoden fra Main-metoden.

statisk ugyldigt Main (streng [] args)

        {

IR-lager: nyt lager ();

var resultat = repository.GetData ();

hvis (resultat.IsFuldført)

Console.WriteLine ("Operation complete ...");

andet

Console.WriteLine ("Drift ufuldstændig ...");

Console.ReadKey ();

        }

Lad os nu tilføje en anden metode til vores lager, denne gang en asynkron metode ved navn GetDataAsync. Her er, hvordan den modificerede IRepository-grænseflade vil se ud.

offentlig grænseflade IR-depot

    {

ValueTask GetData ();

ValueTask GetDataAsync ();

    }

GetDataAsync-metoden implementeres af Repository-klassen som vist i kodestykket nedenfor.

  public class Repository: IRepository

    {

offentlig ValueTask GetData ()

        {

var værdi = standard (T);

returner ny ValueTask (værdi);

        }

offentlig async ValueTask GetDataAsync ()

        {

var værdi = standard (T);

afventer Task.Delay (100);

returværdi

        }

    }

Hvornår skal jeg bruge ValueTask i C #?

Omend de fordele, ValueTask giver, er der visse kompromiser med at bruge ValueTask i stedet for Task. ValueTask er en værditype med to felter, mens Task er en referencetype med et enkelt felt. Derfor betyder brug af en ValueTask at arbejde med flere data, da et metodeopkald ville returnere to datafelter i stedet for et. Også, hvis du afventer en metode, der returnerer en ValueTask, ville tilstandsmaskinen for den asynkrone metode også være større - fordi den skulle rumme en struktur, der indeholder to felter i stedet for en enkelt reference i tilfælde af en opgave.

Hvis forbrugeren af ​​en asynkron metode bruger Task.WhenAll eller Task.WhenAny, kan det blive dyrt at bruge ValueTask som en returtype i en asynkron metode. Dette skyldes, at du bliver nødt til at konvertere ValueTask til Task ved hjælp af AsTask-metoden, hvilket ville medføre en allokering, der let kunne undgås, hvis en cachetask først var blevet brugt.

Her er tommelfingerreglen. Brug Task, når du har et stykke kode, der altid vil være asynkront, dvs. når operationen ikke straks afsluttes. Udnyt ValueTask, når resultatet af en asynkron handling allerede er tilgængelig, eller når du allerede har et cache-resultat. Uanset hvad, skal du udføre den nødvendige præstationsanalyse, før du overvejer ValueTask.

Sådan gør du mere i C #:

  • Sådan bruges uforanderlighed i C
  • Sådan bruges const, readonly og static i C #
  • Sådan bruges datanoteringer i C #
  • Sådan arbejder du med GUID'er i C # 8
  • Hvornår skal man bruge en abstrakt klasse vs. interface i C #
  • Sådan arbejder du med AutoMapper i C #
  • Sådan bruges lambda-udtryk i C #
  • Sådan arbejder du med Action-, Func- og Predicate-delegerede i C #
  • Sådan arbejder du med delegerede i C #
  • Sådan implementeres en simpel logger i C #
  • Sådan arbejder du med attributter i C #
  • Sådan arbejder du med log4net i C #
  • Sådan implementeres depotdesignmønsteret i C #
  • Sådan arbejder du med refleksion i C #
  • Sådan arbejder du med filsystemwatcher i C #
  • Sådan udføres doven initialisering i C #
  • Sådan arbejder du med MSMQ i C #
  • Sådan arbejder du med udvidelsesmetoder i C #
  • Hvordan vi lambda-udtryk i C #
  • Hvornår skal du bruge det flygtige nøgleord i C #
  • Sådan bruges afkastnøgleordet i C #
  • Sådan implementeres polymorfisme i C #
  • Sådan bygger du din egen opgaveplanlægning i C #
  • Sådan arbejder du med RabbitMQ i C #
  • Sådan arbejder du med en tuple i C #
  • Udforskning af virtuelle og abstrakte metoder i C #
  • Sådan bruges Dapper ORM i C #
  • Sådan bruges designmønsteret med flyvægt i C #