Ülesannete või ülesannete klasside kasutamisel on jõudluse kitsaskoht, mida me varasemates artiklites ei maininud. Lühidalt, need tunnid juhivad siis, kui tulemused on kohe kättesaadavadTarbetu jaotus。 See tähendab, et uus ülesanne või ülesande objekt luuakse alati, isegi kui tulemus on juba saadaval. Mainisime, et asünkroonne/ootamise kontseptsioon, mida kasutasime varasemates artiklites, on olnud olemas alates .NET 4.5 versioonist. Seda funktsiooni on täiustatud alates C# 7-st .NET 4.7 versiooniga, millel on ValueTask struktuur, mida saab kasutada asünkroonsete funktsioonide tagastusena.
ValueTask struktuur
ValueTaski struktuur ilmus esmakordselt corefxlabi hoidlasse 2015. aastal. Seda hoidlat kasutatakse uute ideede katsetamiseks ja uurimiseks, mis võivad jõuda või mitte jõuda peamisse corefxi hoidlasse. Corefxi hoidla on hoidla, kus asuvad kõik .NET Core baasteegid. Selle töötas välja ja soovitas Stephen Taub System.Threading.Tasks.Channels teegi jaoks. Sel ajal andis Stephen lühikese selgituse:
Corefxlabi raamatukogu aadress:Hüperlingi sisselogimine on nähtav.
ValueTask on T ja Taski eraldiseisev ühendus, mis võimaldab ReadAsyncil vabalt jaotada, et sünkroonselt tagastada oma saadaolevad T väärtused (erinevalt Task.FromResultist, mis nõuab ülesande instantsi eraldamist). ValueTask on oodatav, seega enamiku instantside tarbimine on eristamatu ülesannete tarbimisest. Paljud inimesed näevad selle struktuuri kasutamise eeliseid, mis on kaasatud C# 7-sse osana System.Threading.Tasks.Extensions NuGet paketist. Enne kui sukeldume ValueTaski struktuuri, vaatame probleemi, mida see lahendab. Kuna Task(Task) on viitetüüp, alustaAsünkroonne meetod, mis tagastab ülesande objekti, tähendab, et see eraldatakse kuhjale iga kord。 See on paljudel juhtudel vajalik.
Kuid mõnel juhul tagastavad asünkroonsed meetodid tulemused kohe või täielikult sünkroonselt. Sellistel juhtudel on see jaotus tarbetu ja võib muutuda kulukaks koodi jõudluse kriitilistes osades. Kuni .NET 4.7 versioonini polnud seda võimalik vältida, kuna asünkroonsed meetodid pidid tagastama Task, Task <T>või void (viimane oli tavaliselt ebasoovitav). Selles .NET versioonis on see laiendatud, mis tähendab, et asünkroonne meetod võib tagastada mis tahes tüübi, kui tal on ligipääsetav GetAwaiteri meetod. ValueTask on selle tüübi konkreetne näide ning see lisati samuti sellesse väljalaskesse.
Saad sirvida corefx repositooriumi ja näha ValueTaski täielikku rakendust, siin on API sektsioon, mis meid huvitab:
Struktuurina võimaldab ValueTask kirjutada asünkroonseid meetodeid, mis ei eralda mälu sünkroonse käivituse ajal. Async/await kontseptsiooni API järjepidevus ei ole sellisel moel kompromiteeritud. Lisaks sellele ootab see struktuur iseseisvalt, muutes selle kasutamise lihtsaks. Näiteks, kui käivitame selle lihtsa koodi:
MultiplyAsync meetodis simuleerime olukorda, kus soovime vältida Taski kasutamist ja tagastada ainult lihtsa täisarvu. See toimub meetodi if-lauses, kus me põhimõtteliselt kontrollime, kas antud parameeter on null. Probleem on selles, etIsegi kui meie tingimus if-lauses on tõene, loob ülaltoodud kood ülesandeobjekti。 Me lahendame selle probleemi nii:
ValueTask ja Task
Nagu varem mainitud, on ValueTaski kasutamisel kaks peamist eelist:
- Jõudluse täiustused
- Suurenda rakendamise paindlikkust
Millised on numbrid jõudluse paranemise taga? Jälgi seda koodi:
Kui me selle koodi käivitame, kulub JIT-i käivitamiseks 120 ns. Nüüd, kui asendada Task ValueTaskiga nii:
JIT-iga saame täitmisajaks 65ns. Tõsi on see, et Task.Delay tõttu me ei täida sünkroonselt, kuid näeme täitmisaja paranemist.
Teine eelis, mida mainisime, on rakenduse suurenenud paindlikkus. Mida see täpselt tähendab? Asünkroonsete liideste teostused, mis peaksid olema sünkroniseeritud, sunnitakse kasutama Task.Run või Task.FromResult. Muidugi viib see varem mainitud jõudlusprobleemideni. Kui kasutame ValueTask'i, valime tõenäolisemalt sünkroonsete või asünkroonsete rakenduste vahel. Pea meeles, et see võib viidata sellele, et su kood ei pruugi olla hästi kujundatud, kui see sinuga juhtub.
Näiteks vaadake seda liidest:
Oletame, et tahad seda koodist välja kutsuda nii:
Kuna liideses kasutab ValueTask'i, võib liidese teostus olla sünkroonne või asünkroonne. Seda kasu saame siis, kui jätame IThingusse mõned funktsioonid vahele, mis haldavad sünkroniseerimiskäitumist. Seda liidest on palju lihtsam nii kasutada. Siin on ülaltoodud liidese sünkroonne teostus:
Siin on sama liidese asünkroonne teostus:
Siiski peame enne ValueTaski kasutamist arvestama mõningate kompromissidega. On lihtne arvata, et vaikimisi peaks kasutama ValueTaski Taski asemel, mis kindlasti nii ei ole. Näiteks, kuigi ValueTask aitab vältida tarbetuid määramisi, kui tulemuste sünkroniseerimine on saadaval, sisaldab see ka kahte välja.
Oluline on meeles pidada, et just seda struktuuri me siin kasutame, mis tähendab, et kasutame väärtustüüpe ja kõiki nende koormaid. Ülesanne seevastu on viitetüüp, millel on ainult üks väli.Kui kasutad ValueTask'i, on meil rohkem andmeid töödelda ja töödelda. Kui sellist meetodit oodatakse asünkroonses meetodis, siis asünkroonne meetod onRiigimasin saab olema ka suurem, sest kogu struktuuri salvestamine nõuab tavaliselt rohkem ruumi kui ühe viite salvestamine.
Seetõttu soovitavad Microsofti inimesed asünkroonsete meetodite vaikimisi tagastustüübina kasutada Task või Task. Alles pärast jõudlusanalüüsi peaksid kaaluma üleminekut ValueTaskile.
Kokkuvõte
ValueTask on struktuur, mis tutvustati .NET 4.7-s ja annab meile palju võimalusi kasutada asünkroonseid meetodeid .NET-is. Kuid see ei ole ilma hinnata. See on kasulik jõudluskriitiliste meetodite puhul, mis täidetakse sünkroonselt. Nende abil saame vältida tarbetute objektide määramist. Siiski, väärtustüübina kaasnevad sellega kõik probleemid, mis väärtustüüpidel tavaliselt on. Seetõttu võime sellest struktuurist kasu saada, kuid peame olema ettevaatlikud.
Algne aadress:Hüperlingi sisselogimine on nähtav.
|