NET: Aaladaha loogu talagalay in lagu shaqeeyo isku-dhufashada iyo asynchrony. Qaybta 1

Waxaan ku daabacayaa maqaalkii asalka ahaa ee Habr, kaas oo tarjumaaddiisa lagu dhejiyay shirkadda boostada blog.

Baahida loo qabo in wax la sameeyo, iyada oo aan la sugin natiijada halkan iyo hadda, ama in la qaybiyo shaqada weyn ee dhowr qaybood oo fulinaysa, waxay jirtay kahor imaatinka kombiyuutarada. Markii ay yimaadeen, baahidani waxay noqotay mid la taaban karo. Hadda, sannadka 2019, waxaan maqaalkan ku qorayaa laptop-ka leh processor-ka 8-core Intel Core, kaas oo in ka badan boqol geeddi-socod ay si is-bar-bar socda u socdaan, iyo weliba dun ka badan. Meel u dhow, waxaa yaalo taleefoon yar oo aan xishood lahayn, oo la iibsaday dhowr sano ka hor, waxa uu saaran yahay processor 8-core ah. Ilaha mawduuca waxaa ka buuxa maqaallo iyo muuqaalo halkaas oo qoraayaashoodu ay u riyaaqaan taleefannada casriga ah ee sanadkan kuwaas oo ka kooban 16-core processor. MS Azure waxa uu bixiyaa mishiin farsamaysan oo leh processor core 20 ah iyo 128 TB RAM wax ka yar $2/saacaddii. Nasiib darro, suurtagal maaha in la soo saaro ugu badnaan oo laga faa'iidaysto awooddan iyada oo aan la awoodin in la maareeyo isdhexgalka dunta.

Eray bixin

Habka - Shayga OS, meel ciwaanka go'doonsan, waxa ku jira dunta.
Dulqaad - shay OS ah, unugga ugu yar ee fulinta, qayb ka mid ah habka, duntu waxay wadaagaan xusuusta iyo agabka kale ee dhexdooda geeddi-socod.
Multitasking - Hantida OS, awoodda ay ku socodsiiso habab dhowr ah isku mar
Multi-core - hanti Processor-ka, awoodda uu u leeyahay in uu isticmaalo dhawr nooc oo xog ah
Farsamaynta badan - hanti kombuyuutar, awood u leh inuu isku mar la shaqeeyo dhowr processor oo jir ahaan ah
Multithreading - hanti geeddi-socod, awood u leh in lagu qaybiyo hab-socodka xogta dhowr qaybood oo kala duwan.
Isbarbar yaac - Samaynta dhawr fal oo jidh ahaan isku mar ah halbeegkiiba
Asynchrony - fulinta hawlgalka iyada oo aan la sugin dhamaystirka habraacan; natiijada fulinta ayaa laga baaraandegi karaa mar dambe.

Tusaale ahaan

Qeexitaannada oo dhami ma fiicna qaarna waxay u baahan yihiin sharraxaad dheeraad ah, markaa waxaan ku dari doonaa tusaale ku saabsan karinta quraacda ereybixinta rasmiga ah ee la soo bandhigay. Quraacda karinta ee tusaalahan waa habsocod.

Anigoo diyaarinaya quraac subaxdii ayaan (processorWaxaan imid jikada (Kombuyuutar). Waxaan haystaa 2 gacmood (diirkja). Waxaa jira tiro qalab ah oo kushiinka ah (IO): foornada, kildiga, rootiga, qaboojiyaha. Waxaan shidayaa gaaska, waxa aan dulsaaraa digsi shiilan oo aan saliid ku shubaa aniga oo aan sugin in ay kululaato (si isku mid ah, aan la xannibin-IO-Sug), Ukunta ayaan talaagada kala soo baxaa oo waxaan ku jebiyaa saxan, kadibna hal gacan ayaan ku garaacayDulqaadka #1iyo labaad (Dulqaadka #2) haysta saxanka (Shared Resources). Hadda waxaan jeclaan lahaa inaan shido kiliyaha, laakiin ma haysto gacmo igu filan (Dul gaajo) Inta lagu jiro wakhtigan, digsiga shiilan ayaa kululaada (Ka-hortagga natiijada) kaas oo aan ku shubo wixii aan garaacay. Waxa aan soo gaadhay kildhigii oo aan shiday waxaanan si doqonnimo ah u daawadaa biyaha oo ku karkaraya (Joojinta-IO-Sug), inkasta oo uu wakhtigan ku dhaqi karay saxankii uu ku karbaashay omelet.

Waxaan ku karsaday omelette anoo isticmaalaya 2 gacmood oo kaliya, wax badanna ma hayo, laakiin isla markaa, wakhtiga garaaca omelette, 3 qalliin ayaa hal mar wada dhacay: garaaca omelette, qabashada saxanka, kululaynta digsiga shiilan. CPU-gu waa qaybta ugu dhaqsiyaha badan kombiyuuterka, IO waa waxa ugu badan ee wax walba hoos u dhacaan, inta badan xal wax ku ool ah ayaa ah in CPU lagu mashquuliyo shay iyadoo xogta IO laga helayo.

Sii wad hadalka:

  • Haddii habka diyaarinta omelet, waxaan sidoo kale isku dayi lahaa inaan beddelo dharka, tani waxay tusaale u noqon kartaa hawlo badan. Nuance muhiim ah: kombiyuutarada ayaa tan aad uga fiican dadka.
  • Jikada leh cunto kariye dhowr ah, tusaale ahaan makhaayad - kombuyuutar badan oo asaasi ah.
  • Makhaayado badan oo ku yaal barxadda cuntada ee xarunta wax iibsiga - xarunta xogta

NET Tools

NET waxay ku fiican tahay la shaqaynta dunta, sida waxyaabo kale oo badan. Nooc kasta oo cusub, waxa uu soo bandhigayaa qalab cusub oo badan oo lagula shaqaynayo, lakabyo cusub oo la taaban karo oo ka badan dunta OS. Markaad la shaqeyneyso dhisidda naqshadaha, horumarinta qaab-dhismeedka waxay isticmaalaan hab ka tagaya fursadda, marka la isticmaalayo aabstraction heer sare ah, si ay hoos ugu dhaadhacaan hal ama dhowr heerar. Inta badan tani lagama maarmaan maaha, run ahaantii waxay furto albaabka in aad lugtaada ku toogto qoriga toogashada ah, laakiin mararka qaarkood, marar dhif ah, waxay noqon kartaa habka kaliya ee lagu xalliyo dhib aan la xalin heerka hadda la joogo. .

Qalab ahaan, waxaan ula jeedaa labadaba codsiyada barnaamijka interneedka (APIs) ee ay bixiyaan qaab-dhismeedka iyo xirmooyinka dhinac saddexaad, iyo sidoo kale dhammaan xalalka softiweerka ah ee fududeynaya raadinta dhibaatooyin kasta oo la xiriira koodka-threaded-ka badan.

Bilaabida dunta

Fasalka Thread waa fasalka ugu aasaasiga ah ee .NET si loogu shaqeeyo dunta. Dhisuhu wuxuu aqbalayaa mid ka mid ah labada ergo:

  • ThreadStart - Ma jiraan wax xaddidan
  • ParametrizedThreadStart - oo leh hal cabbir oo shay ah.

Ergada waxaa lagu fulin doonaa dunta cusub ee la sameeyay kadib marka la wacayo habka Start.Haddii ergo nooca ParametrizedThreadStart loo gudbiyo dhisaha, markaas shay waa in loo gudbiyaa habka Start. Habkan ayaa loo baahan yahay si loogu wareejiyo xog kasta oo maxalli ah oo ku socota qulqulka. Waxaa xusid mudan in abuurista duntu ay tahay qalliin qaali ah, duntu lafteedu waa shay culus, ugu yaraan sababtoo ah waxay u qoondaysaa 1MB oo xusuusta ah ee xidhmada waxayna u baahan tahay isdhexgalka OS API.

new Thread(...).Start(...);

Fasalka ThreadPool wuxuu matalaa fikradda barkadda. Gudaha NET, barkada duntu waa qayb ka mid ah injineernimada, horumarinta Microsoft waxay sameeyeen dadaal badan si ay u hubiyaan inay si fiican ugu shaqeyso xaalado kala duwan oo kala duwan.

Fikradda guud:

Laga bilaabo wakhtiga uu arjigu bilaabmayo, waxa ay abuurtaa dhawr xadhig oo kayd ah gadaasha waxana ay siisaa awooda loo isticmaalo. Haddi dunta si joogta ah loo isticmaalo iyo tiro badan, barkadu way balaartaa si ay u daboosho baahida qofka soo wacaya. Marka aanay jirin dunta bilaashka ah ee barkada wakhtiga saxda ah, waxay sugi doontaa mid ka mid ah dunta soo noqoshada, ama waxay abuuri doontaa mid cusub. Waxay soo raacdaa in barkada duntu ay ku fiican tahay qaar ka mid ah ficilada wakhtiga gaaban oo ay liidato ku habboon hawlgallada u socda adeeg ahaan inta lagu jiro hawlgalka arjiga oo dhan.

Si aad u isticmaasho dunta barkada, waxa jira habka QueueUserWorkItem kaas oo aqbala ergo nooca WaitCallback ah, kaas oo leh saxeex la mid ah ParametrizedThreadStart, cabirka loo soo gudbiyayna waxa uu qabtaa shaqo la mid ah.

ThreadPool.QueueUserWorkItem(...);

Habka barkadda dunta dunta ee yar ee la yaqaan RegisterWaitForSingleObject waxa loo isticmaalaa in lagu abaabulo hawlgallada IO ee aan xannibin. Ergeyga loo gudbiyay habkan waxa la wici doona marka WaitHandle u gudbo habka "Lasii daayo".

ThreadPool.RegisterWaitForSingleObject(...)

NET waxa ay leedahay saacada dunta waxayna kaga duwan tahay WinForms/WPF wakhtiyada in maamuleheeda loogu yeedhi doono dun laga soo qaaday barkada.

System.Threading.Timer

Waxa kale oo jirta hab aad u qalaad oo loogu diri karo ergo fulinta dunta barkada - habka BeginInvoke.

DelegateInstance.BeginInvoke

Waxaan jeclaan lahaa inaan si kooban u dul istaago shaqada ay qaar badan oo ka mid ah hababka kor ku xusan loogu yeeri karo - CreateThread from Kernel32.dll Win32 API. Waxaa jira hab, mahadsanid habka hababka dibadda, si loogu yeero shaqadan. Waxaan ku arkay baaq noocaas ah hal mar oo kaliya tusaale xun oo ah xeerka dhaxalka, iyo dhiirigelinta qoraaga sida saxda ah sameeyay ayaa wali ii ah qarsoodi.

Kernel32.dll CreateThread

Daawashada iyo Dejinta Xadhkaha

Xargaha aad adigu samaysay, dhammaan qaybaha saddexaad, iyo barkada NET waxa laga eegi karaa daaqada Threads ee Visual Studio. Daaqadani waxay soo bandhigi doontaa kaliya macluumaadka dunta marka codsiga uu ku jiro debug iyo qaabka Break. Halkan waxa aad si ku habboon u eegi kartaa magacyada isku xidhan iyo mudnaanta dun kasta, oo aad u beddesho khaladka dun gaar ah. Isticmaalka hantida mudnaanta leh ee fasalka Thread, waxaad dejin kartaa mudnaanta dunta, taas oo OC iyo CLR ay u arki doonaan talo ahaan marka loo qaybinayo wakhtiga processor-ka ee u dhexeeya dunta.

NET: Aaladaha loogu talagalay in lagu shaqeeyo isku-dhufashada iyo asynchrony. Qaybta 1

Laybareeriga barbar socda Hawsha

Laybareeriga Isbarbar-dhigga Hawsha (TPL) ayaa lagu soo bandhigay .NET 4.0. Hadda waa heerka iyo qalabka ugu muhiimsan ee la shaqeynta asynchony. Koodh kasta oo isticmaala hab hore ayaa loo tixgeliyaa dhaxal. Unugga aasaasiga ah ee TPL waa fasalka Task ee nidaamka.Threading.Tasks namespace. Hawshu waa duleel dul saaran. Nooca cusub ee luqadda C #, waxaan helnay hab qurux badan oo aan ula shaqeyno Hawlaha - async/wait operators. Fikradahani waxay suurtogal ka dhigeen in la qoro koodka asynchronous sida haddii ay tahay mid fudud oo isku mid ah, tani waxay suurtogal ka dhigtay xitaa dadka fahamka yar ee shaqada gudaha ee dunta si ay u qoraan codsiyada isticmaala iyaga, codsiyada aan barafeynin marka ay fulinayaan hawlgallo dheer. Isticmaalka async/sugid waa mawduuc hal ama xitaa dhowr maqaallo ah, laakiin waxaan isku dayi doonaa inaan dulucda jumlada ku helo dhawr weedho:

  • async waa wax ka beddelka habka soo celinta Hawsha ama faaruqinta
  • iyo sugitaanka waa hawlwadeenka sugitaanka Hawsha aan xannibin.

Mar labaad: hawlwadeenka sugitaanka, guud ahaan (waxaa jira waxyaabo ka reeban), ayaa sii deyn doona dunta hadda jirta ee fulinta, iyo marka Hawshu dhamaato fulinteeda, iyo dunta (xaqiiqda, waxay noqon doontaa mid sax ah in la yiraahdo macnaha guud. , laakiin inbadan oo intaas ka dib) way sii wadi doontaa fulinta habka. Gudaha .NET, habkan waxaa loo fuliyaa si la mid ah soo-celinta wax-soo-saarka, marka habka qorani uu isu beddelo fasalka oo dhan, kaas oo ah mishiinka dawladda waxaana lagu fulin karaa qaybo kala duwan iyadoo ku xiran gobolladan. Qof kasta oo danaynaya waxa uu qori karaa kood kasta oo fudud isaga oo isticmaalaya asynс/sugi, ururin iyo eegi karaa kulanka iyaga oo isticmaalaya JetBrains dotPeek oo leh Code-ka Soo-samaynta Kombiyuutarka oo karti leh.

Aynu eegno fursadaha bilaabista iyo isticmaalka Hawsha. Tusaalaha koodka hoose, waxaanu abuurnaa hawl cusub oo aan waxba faa'iido ah samayn (Dul.Hurdo(10000)), laakiin nolosha dhabta ah tani waa inay noqotaa shaqo adag oo CPU ah.

using TCO = System.Threading.Tasks.TaskCreationOptions;

public static async void VoidAsyncMethod() {
    var cancellationSource = new CancellationTokenSource();

    await Task.Factory.StartNew(
        // Code of action will be executed on other context
        () => Thread.Sleep(10000),
        cancellationSource.Token,
        TCO.LongRunning | TCO.AttachedToParent | TCO.PreferFairness,
        scheduler
    );

    //  Code after await will be executed on captured context
}

Hawsha waxa lagu abuuray dhawr doorasho:

  • LongRunning waa tilmaan in hawshu aan si dhakhso ah loo dhamaystirin, taas oo macnaheedu yahay in laga yaabo inay mudan tahay in la tixgeliyo inaan dun laga soo qaadin barkadda, laakiin loo abuuro mid gaar ah Hawshan si aan loo dhibaatayn kuwa kale.
  • AttachedToParent - Hawlaha waxaa lagu diyaarin karaa heer sare. Haddii doorashadan la isticmaalay, markaas Hawshu waxay ku jiri kartaa xaalad iyada lafteedu ay dhammaystirtay oo ay sugayso dilitaanka carruurteeda.
  • Dookhnimada - waxay ka dhigan tahay inay fiicnaan lahayd in la fuliyo Hawlaha loo diray fulinta ka hor inta aan dib loo dirin. Laakiin tani waa talo uun, natiijooyinkuna lama dammaanad qaadayaan.

Halbeegga labaad ee loo gudbiyay habka waa CancelationToken. Si loo saxo baabi'inta hawlgalka ka dib marka uu bilowdo, koodka la fulinayo waa in lagu buuxiyaa jeegaga gobolka CancelationToken. Haddii aysan jirin jeegag, markaa habka Joojinta ee loogu yeero CancellationTokenSource shayga wuxuu awoodi doonaa inuu joojiyo fulinta Hawsha ka hor intaysan bilaabmin.

Halbeegga u dambeeya waa shay jadwaleeyaha nooca TaskScheduler. Fasalkan iyo faraciisa waxa loo qaabeeyey in ay maamulaan xeeladaha lagu qaybinayo hawlaha dunta oo dhan; sida caadiga ah, Hawsha waxa lagu fulin doonaa dun aan kala sooc lahayn oo ka socota barkadda.

Hawlwadeenka sugitaanka waxaa lagu dabaqaa Hawsha la abuuray, taas oo macnaheedu yahay koodka la qoray ka dib, haddii uu jiro, waxaa lagu fulin doonaa isla macnaha (inta badan tani waxay ka dhigan tahay isla dunta) sida koodka ka hor intaan la sugin.

Habka waxaa loo calaamadeeyay sida async void, taas oo macnaheedu yahay inay isticmaali karto hawlwadeenka sugitaanka, laakiin lambarka wicitaanku ma sugi doono fulinta. Haddii sifada noocan oo kale ah ay lagama maarmaan tahay, markaa habka waa inuu soo celiyaa Hawsha. Hababka lagu calaamadiyay async void waa wax caadi ah: sida caadiga ah, kuwani waa maareeyaha dhacdada ama habab kale oo ka shaqeeya dabka oo ilooba mabda'a. Haddii aad u baahan tahay inaadan kaliya siin fursad aad ku sugto ilaa dhamaadka fulinta, laakiin sidoo kale soo celi natiijada, markaa waxaad u baahan tahay inaad isticmaasho Hawsha.

Hawsha uu habka StartNew soo laabtay, iyo sidoo kale mid kasta oo kale, waxaad wici kartaa habka ConfigureAwait oo leh cabbirka beenta ah, ka dib fulinta sugidda ka dib ma sii socon doonto macnaha guud ee la qabtay, laakiin mid aan sabab lahayn. Tan waa in had iyo jeer la sameeyaa marka macnaha fulinta uusan muhiim u ahayn koodka sugidda ka dib. Tani sidoo kale waa talo ka timid MS marka la qorayo koodka kaas oo lagu keeni doono baakad ahaan maktabadda.

Bal aan in yar yara dul istaagno sida aad u sugi karto dhammaystirka Hawsha. Hoos waxaa ku yaal tusaale kood ah, oo leh faallooyin ku saabsan marka rajada loo sameeyo shuruud ahaan si wanaagsan iyo marka si shuruud la'aan ah loo sameeyo.

public static async void AnotherMethod() {

    int result = await AsyncMethod(); // good

    result = AsyncMethod().Result; // bad

    AsyncMethod().Wait(); // bad

    IEnumerable<Task> tasks = new Task[] {
        AsyncMethod(), OtherAsyncMethod()
    };

    await Task.WhenAll(tasks); // good
    await Task.WhenAny(tasks); // good

    Task.WaitAll(tasks.ToArray()); // bad
}

Tusaalaha ugu horreeya, waxaan sugayna in Hawshu ay dhammaato iyada oo aan la xannibin dunta wicitaanka; waxaan ku soo laaban doonnaa socodsiinta natiijada kaliya marka ay horay u jirtay; ilaa markaas, dunta wicitaanka ayaa loo daayaa qalabkeeda.

Doorashada labaad, waxaanu xannibnaa dunta wacitaanka ilaa natiijada habka la xisaabiyo. Tani waa xun ma aha oo kaliya sababtoo ah waxaan ku mashquulin dun, sida kheyraadka qiimaha leh ee barnaamijka, oo leh shaqo-la'aan fudud, laakiin sidoo kale sababtoo ah haddii code habka in aan wacnay ka kooban yahay sugto, iyo macnaha isku-duubni u baahan yahay ku soo laabashada dunta wac ka dib. Sug, ka dibna waxaan heli doonaa xannibaad: Dufan wicitaanku wuxuu sugayaa natiijada habka asynchronous si loo xisaabiyo, habka asynchronous wuxuu isku dayaa si aan waxtar lahayn inuu sii wado fulinta ee dunta wacitaanka.

Khasaaraha kale ee habkani waa maaraynta khaladka adag. Xaqiiqdu waxay tahay in khaladaadka koodka asynchronous marka la isticmaalayo asynchronous/sugidda ay aad u fududahay in wax laga qabto - waxay u dhaqmaan si la mid ah haddii koodka uu isku mid yahay. Halka haddii aan ku dabaqno ka saarista sugitaan isku mid ah Hawsha, ka reebida asalka ah waxay isu beddeshaa AggregateException, i.e. Si aad u xalliso waxa ka reeban, waa inaad baartaa nooca InnerException oo aad ku qorto silsilad gudaha hal block ama isticmaal qabsashada marka la dhisayo, halkii aad ka ahaan lahayd silsiladaha qabsashada ee aad looga yaqaan C # aduunka.

Tusaalooyinka saddexaad iyo kan ugu dambeeya ayaa sidoo kale lagu calaamadeeyay inay xun yihiin isla sabab isku mid ah waxayna ka kooban yihiin dhammaan dhibaatooyin isku mid ah.

Marka kasta iyo markaDhammaan hababka ayaa aad ugu habboon in la sugo koox Hawlo ah; waxay ku duubaan koox Hawleed mid, kuwaas oo dab ka qaadi doona midkood marka hawsha kooxda marka hore la kiciyo, ama marka dhammaantood dhammeeyaan fulinta.

Joojinta dunta

Sababo kala duwan dartood, waxaa laga yaabaa inay lagama maarmaan noqoto in la joojiyo socodka ka dib marka uu bilaabo. Waxaa jira dhowr siyaabood oo tan loo sameeyo. Fasalka Thread wuxuu leeyahay laba hab oo si habboon loo magacaabay: Soo rid и go'do. Midka ugu horreeya aad looguma talinayo in la isticmaalo, sababtoo ah ka dib markaad wacdo daqiiqad kasta oo aan kala sooc lahayn, inta lagu guda jiro habaynta tilmaanta, ka reeban ayaa la tuurayaa ThreadAbortedException. Ma filaysid ka-reebis caynkaas oo kale ah in lagu tuuro marka la kordhinayo doorsoomayaasha shaandhada, sax? Iyo marka la isticmaalayo habkan, tani waa xaalad aad u dhab ah. Haddii aad u baahan tahay inaad ka hortagto CLR inuu soo saaro ka reebanaanshahan oo kale qayb gaar ah oo kood ah, waxaad ku duubi kartaa wicitaannada Dulqaad.Bilow Gobolka Critical, Thread.EndCriticalGobolka. Koodh kasta oo ku qoran block ugu dambeyntii wuxuu ku duudduubay wicitaanada noocaas ah. Sababtan awgeed, qoto dheer ee koodhka qaab-dhismeedka waxaad ka heli kartaa baloogyo leh isku day maran, laakiin ugu dambeyntii madhan madhan. Microsoft aad ayay u niyad jabisaa habkan oo aanay ku darin .net core.

Habka kala-joojinta wuxuu u shaqeeyaa si la saadaalin karo. Waxay ka joojin kartaa dunta marka laga reebo ThreadInterruptedException kaliya inta lagu jiro daqiiqadahaas marka duntu ku jirto xaalad sugitaan. Waxa ay gashaa xaaladan marka ay ka laadlaadsan tahay WaitHandle, quful, ama ka dib marka ay wacdo Thread.Sleep.

Labada doorasho ee kor lagu sharaxay waa kuwo xun sababtoo ah lama saadaalin karo. Xalku waa in la isticmaalo qaab dhismeed CancellationToken iyo fasalka CancelationTokenSource. Ujeedadu waa tan: tusaale fasalka CancellationTokenSource ayaa la sameeyay oo kan kaliya ayaa joojin kara hawlgalka isagoo wacaya habka Cancel. Kaliya CancelationToken ayaa loo gudbiyaa hawlgalka laftiisa. Milkiilayaasha CancelationToken laftoodu ma burin karaan hawlgalka, laakiin waxay hubin karaan oo keliya in hawlgalka la joojiyay. Waxaa jira hanti reer Boole ah tan Joojinta ayaa la codsaday iyo habka Tuur Haddii la joojiyo la codsaday. Ka dambe wuxuu tuurayaa ka reebis Hawsha la joojiyay haddii habka Cancel loogu yeedhay tusaale ahaan CancelationToken oo la sii daayay. Tanina waa habka aan ku talinayaa in la isticmaalo. Tani waxay horumar ka tahay doorashooyinkii hore iyadoo si buuxda loo xakameynayo marka laga reebo qalliinka la soo ridi karo.

Xulashada ugu naxariista daran ee joojinta duntu waa in la waco Win32 API TerminateThread function. Dhaqanka CLR ka dib marka uu soo waco shaqadan waxa laga yaabaa inaan la saadaalin karin. On MSDN waxa ku qoran hawshan: "TerminateThread waa hawl khatar ah oo ay tahay in la isticmaalo oo keliya xaaladaha ugu daran. "

U beddelashada dhaxalka API ee Hawsha ku saleysan iyadoo la adeegsanayo habka FromAsync

Haddii aad nasiib u leedahay inaad ka shaqeyso mashruuc la bilaabay ka dib markii Hawlaha la soo bandhigay oo la joojiyay inay u horseedaan cabsi aamusnaan badan horumarinta, markaa uma baahnid inaad wax ka qabato API-yo badan oo duug ah, labada dhinac saddexaad iyo kuwa kooxdaada. hore u jirdilay. Nasiib wanaag, kooxda .NET Framework ayaa na daryeelay, inkasta oo laga yaabo in ujeedadu ahayd inaan is daryeelno. Si kastaba ha ahaatee, NET waxa ay haysaa tiro qalab ah oo si xanuun la'aan ah loogu beddelo koodka oo ku qoran hababkii hore ee barnaamijka asynchronous ee kan cusub. Mid ka mid ah waa habka FromAsync ee TaskFactory. Tusaalaha koodka hoose, waxaan ku duubaa hababkii hore ee assync ee fasalka WebRequest ee Hawsha anigoo isticmaalaya habkan.

object state = null;
WebRequest wr = WebRequest.CreateHttp("http://github.com");
await Task.Factory.FromAsync(
    wr.BeginGetResponse,
    we.EndGetResponse
);

Tani waa tusaale kaliya oo uma badna inaad tan ku sameyso noocyo ku dhex jira, laakiin mashruuc kasta oo duug ah ayaa si fudud ula socda hababka BeginDoSomething ee soo celiya IAsyncResult iyo EndDoSomething hababka hela.

U beddelo dhaxalka API Haw ku salaysan adoo isticmaalaya fasalka TaskCompletionSource

Qalab kale oo muhiim ah in la tixgeliyo waa fasalka TaskCompletionSource. Marka la eego shaqooyinka, ujeedada iyo mabda'a hawlgalka, waxa laga yaabaa inay wax uun xasuusinayso habka RegisterWaitForSingleObject ee fasalka ThreadPool, oo aan korka ka qoray. Isticmaalka fasalkan, waxaad si fudud oo habboon ugu duubi kartaa API-yadii hore ee asynchronous ee Hawlaha.

Waxaad dhihi doontaa inaan horay uga hadlay habka FromAsync ee fasalka TaskFactory ee loogu talagalay ujeedooyinkan. Halkan waa inaan ku xasuusan doonaa dhammaan taariikhda horumarinta moodooyinka asynchronous ee .net ee Microsoft ay bixisay 15kii sano ee la soo dhaafay: ka hor Habka Asynchronous Asynchronous (TAP), waxaa jiray Habka Asynchronous Programming Pattern (APP), kaas oo wuxuu ku saabsanaa hababka bilowWax soo noqda Natiijooyinka IAsync iyo hababka EndDoSomething oo aqbala iyo dhaxalka sanadahaan habka FromAsync waa mid aad u fiican, laakiin waqti ka dib, waxaa bedelay Habka Asynchronous Event Based Asynchronous (EAP), kaas oo u qaatay in dhacdo la kici doono marka hawlgalka asynchronous dhamaado.

TaskCompletionSource waxay ku fiican tahay duubista Hawlaha iyo API-yada dhaxalka ah ee laga dhisay qaabka dhacdada. Nuxurka shaqadeedu waa sida soo socota: shayga fasalkani wuxuu leeyahay hanti dadweyne oo ah nooca Hawsha, xaaladaas oo lagu xakameyn karo SetResult, SetException, iwm. hababka fasalka TaskCompletionSource. Meelaha hawlwadeenka sugitaanka lagu dabaqay Hawshan, waa la fulin doonaa ama ku guul-darraysan doonaa marka laga reebo iyadoo ku xidhan habka lagu dabaqay TaskCompletionSource. Haddii aysan weli caddayn, aan eegno tusaalahan koodka, halkaas oo qaar ka mid ah EAP API-ga lagu duuduubay Hawl iyadoo la adeegsanayo TaskCompletionSource: marka ay dhacdada gubato, Hawsha waxaa loo wareejin doonaa gobolka Dhameystiran, iyo habka loo adeegsaday hawlwadeenka sugitaanka Hawshani waxay dib u bilaabi doontaa fulinteeda markay heshay shayga natiijada.

public static Task<Result> DoAsync(this SomeApiInstance someApiObj) {

    var completionSource = new TaskCompletionSource<Result>();
    someApiObj.Done += 
        result => completionSource.SetResult(result);
    someApiObj.Do();

    result completionSource.Task;
}

TaskCompletionSource Talooyin & Tabaha

Duubista API-yadii hore ma aha waxa la samayn karo iyadoo la isticmaalayo TaskCompletionSource. Isticmaalka fasalkan wuxuu furayaa suurtagalnimada xiisaha leh ee naqshadaynta API-yada kala duwan ee Hawlaha aan lagu mashquulin dunta. Durdurku, sida aan xasuusanno, waa kheyraad qaali ah oo nambarkooda ayaa xaddidan (badanaa qaddarka RAM). Xaddidaaddan si fudud ayaa lagu gaari karaa iyadoo la horumarinayo, tusaale ahaan, codsi shabakadeed oo raran oo leh caqli-gal ganacsi oo adag. Aynu tixgelinno fursadaha aan ka hadlayo marka aan fulinayo khiyaamadan sida Long-Polling.

Marka la soo koobo, nuxurka khiyaamada waa tan: waxaad u baahan tahay inaad ka hesho macluumaadka API ee ku saabsan dhacdooyinka qaarkood ee ka dhacaya dhinaceeda, halka API, sababo qaar, aysan soo sheegi karin dhacdada, laakiin kaliya waxay soo celin kartaa gobolka. Tusaalaha kuwan waxaa ka mid ah dhammaan API-yada lagu dhisay HTTP-yada ka hor waqtiyada WebSocket ama marka ay suurtagal ahayn sabab qaar ka mid ah in la isticmaalo tignoolajiyadan. Macmiilku wuxuu weydiin karaa server-ka HTTP. Seerfarka HTTP laftiisu ma bilaabi karo xidhiidhka macmiilka. Xalka fudud ayaa ah in ra'yi ururin lagu sameeyo server-ka iyada oo la adeegsanayo timer, laakiin tani waxay abuurtaa culeys dheeraad ah oo ku saabsan server-ka iyo dib u dhac dheeraad ah oo ku yimaada celceliska TimerInterval / 2. Si taas loo gaaro, waxaa la abuuray khiyaamo la yiraahdo Long Polling, taas oo ku lug leh dib u dhigista jawaabta server-ka ilaa wakhtigu ka dhacayo ama dhacdo ayaa dhici doonta. Haddii ay dhacdadu dhacday, ka dibna waa la habeeyey, haddii kale, markaa codsiga mar kale ayaa loo soo diraa.

while(!eventOccures && !timeoutExceeded)  {

  CheckTimout();
  CheckEvent();
  Thread.Sleep(1);
}

Laakiin xalka noocan oo kale ah wuxuu caddayn doonaa inuu yahay mid aad u xun isla marka tirada macaamiisha sugaya dhacdada ay korodho, sababtoo ah ... Macmiil kasta oo noocaas ah waxa uu hayaa dunta oo dhan oo sugaysa dhacdo. Haa, oo waxaan helnaa dib u dhac 1ms oo dheeri ah marka dhacdada la kiciyo, inta badan tani maahan mid muhiim ah, laakiin maxay tahay sababta software-ka uga sii xumaatay inta uu noqon karo? Haddii aan meesha ka saarno Thread.Sleep(1), markaas micne la'aan waxaan ku shubi doonaa hal processor core 100% shaqo la'aan, oo ku wareegaysa wareeg aan faa'iido lahayn. Adigoo isticmaalaya TaskCompletionSource waxaad si fudud dib u samayn kartaa summadan oo aad u xallin kartaa dhammaan dhibaatooyinka kor lagu sheegay:

class LongPollingApi {

    private Dictionary<int, TaskCompletionSource<Msg>> tasks;

    public async Task<Msg> AcceptMessageAsync(int userId, int duration) {

        var cs = new TaskCompletionSource<Msg>();
        tasks[userId] = cs;
        await Task.WhenAny(Task.Delay(duration), cs.Task);
        return cs.Task.IsCompleted ? cs.Task.Result : null;
    }

    public void SendMessage(int userId, Msg m) {

        if (tasks.TryGetValue(userId, out var completionSource))
            completionSource.SetResult(m);
    }
}

Koodhkani maaha wax soo saar-diyaar, laakiin kaliya demo. Si aad u isticmaasho kiisaska dhabta ah, waxaad sidoo kale u baahan tahay, ugu yaraan, inaad maareyso xaalada marka fariintu timaado waqti aan cidina filaynin: kiiskan, habka AsseptMessageAsync waa inuu soo celiyaa Hawl hore loo dhammeeyey. Haddii tani ay tahay kiiska ugu badan, markaa waxaad ka fikiri kartaa isticmaalka ValueTask.

Markaan helno codsiga fariinta, waxaan abuurnaa oo dhignaa TaskCompletionSource qaamuuska, ka dibna waxaan sugeynaa waxa dhacaya marka hore: wakhtiga la cayimay wuu dhacayaa ama fariin ayaa la helay.

ValueTask: sababta iyo sida

Hawl-wadeennada async/sugidda, sida soo-celinta soo-celinta soo-saarka, waxay soo saaraan mashiinka gobolka ee habka, tani waa abuurista shay cusub, taas oo mar walba aan muhiim ahayn, laakiin marar dhif ah waxay abuuri kartaa dhibaato. Kiiskan ayaa laga yaabaa inuu yahay hab loo yaqaan runtii marar badan, waxaan ka hadlaynaa tobanaan iyo boqolaal kun oo wicitaan ah ilbiriqsi kasta. Haddii habkan oo kale loo qoro si ay inta badan kiisaska u soo celiso natiijada ka gudubta dhammaan hababka sugitaanka, markaa .NET waxay bixisaa qalab si loo hagaajiyo tan - qaabka ValueTask. Si loo caddeeyo, aan eegno tusaale ahaan isticmaalkeeda: waxaa jira kayd aan marar badan aadno. Waxaa jira qaar qiyam ah oo ku jira ka dibna si fudud ayaan u soo celinaynaa; haddii kale, markaa waxaan aadeynaa IO gaabis ah si aan u helno. Waxaan rabaa in aan sameeyo tan dambe si aan kala sooc lahayn, taas oo macnaheedu yahay in habka oo dhan uu isu rogo in uu noqdo asynchronous. Haddaba, habka cad ee habka loo qoro waa sida soo socota:

public async Task<string> GetById(int id) {

    if (cache.TryGetValue(id, out string val))
        return val;
    return await RequestById(id);
}

Sababtoo ah rabitaanka in wax yar la hagaajiyo, iyo cabsi yar oo laga qabo waxa Roslyn ay dhalin doonto marka la ururinayo koodkan, waxaad dib u qori kartaa tusaalahan sida soo socota:

public Task<string> GetById(int id) {

    if (cache.TryGetValue(id, out string val))
        return Task.FromResult(val);
    return RequestById(id);
}

Runtii, xalka ugu fiican ee kiiskani wuxuu noqon doonaa in la wanaajiyo dariiqa kulul, taas oo ah, helitaanka qiimaha qaamuuska iyada oo aan wax qoondayn ah oo aan loo baahnayn iyo culeys ku saaran GC, halka kiisaska naadir ah marka aan wali u baahanahay inaan u aadno IO xogta. , wax walba waxa ay ahaan doonaan wax lagu daray / laga jaray qaabkii hore:

public ValueTask<string> GetById(int id) {

    if (cache.TryGetValue(id, out string val))
        return new ValueTask<string>(val);
    return new ValueTask<string>(RequestById(id));
}

Aynu si qoto dheer u eegno qaybtan code: haddii ay jirto qiimo ku jirta kaydka, waxaanu abuurnaa qaab-dhismeed, haddii kale hawsha dhabta ah waxay ku duuduuban doontaa mid macno leh. Koodhka wicitaanku ma daneeyo dariiqa koodkan lagu fuliyay: ValueTask, marka laga eego aragtida syntax ee C #, waxay u dhaqmaysaa la mid ah hawsha caadiga ah ee kiiskan.

TaskSchedulers: maaraynta xeeladaha bilowga hawsha

API soo socda ee aan jeclaan lahaa inaan tixgeliyo waa fasalka Jadwalka Hawsha iyo asalkiisa. Waxaan horeba kor ugu xusay in TPL ay awood u leedahay inay maamusho xeeladaha lagu qaybinayo hawlaha dunta. Xeeladaha noocaan ah waxaa lagu qeexay faraca fasalka TaskScheduler. Ku dhawaad ​​xeelad kasta oo aad u baahan karto waxaa laga heli karaa maktabadda. ParallelExtensionsExtras, oo ay samaysay Microsoft, laakiin aan qayb ka ahayn .NET, laakiin loo keenay xirmo Nuget ah. Aynu si kooban u eegno qaar ka mid ah:

  • JadwalkaHawlaha Hadda-Thread - fuliyaa hawlaha dunta hadda
  • Jadwalka Hawsha Hawsha Xakamaynta ee xadidan - waxay xaddidaysaa tirada hawlaha isku mar lagu fuliyay halbeegga N, kaas oo laga aqbalo dhisaha
  • Jadwalka Hawsha La Dalbaday - waxaa lagu qeexaa sida LimitedConcurrencyLevelTaskScheduler(1), markaa hawlaha waxa loo fulin doonaa si isdaba joog ah.
  • Jadwalka Shaqada Xatooyada Shaqada - fulisa tuugo shaqo habka loo qaybiyo hawsha. Asal ahaan waa ThreadPool gooni ah. Wuxuu xalliyaa dhibaatada in NET ThreadPool uu yahay fasalka taagan, mid ka mid ah codsiyada oo dhan, taas oo macnaheedu yahay in xad-dhaafka ah ama isticmaalka khaldan ee qayb ka mid ah barnaamijka ay u horseedi karto waxyeelo kale. Waxaa intaa dheer, aad bay u adag tahay in la fahmo sababta cilladahaas. Taasi. Waxaa laga yaabaa inay jirto baahi loo adeegsado isticmaalka WorkStealingTaskSchedulers gaar ah qaybo ka mid ah barnaamijka halkaasoo isticmaalka ThreadPool laga yaabo inuu noqdo mid dagaal badan oo aan la saadaalin karin.
  • QueuedTaskJadwalka - Waxay kuu ogolaanaysaa inaad qabato hawlaha sida waafaqsan xeerarka safka mudnaanta
  • ThreadPerTaskScheduler - Waxay u abuurtaa dun gaar ah Hawl kasta oo lagu fuliyo dusheeda. Waxay faa'iido u yeelan kartaa hawlaha qaadanaya waqti dheer oo aan la saadaalin karin in la dhammaystiro.

Waxaa jira tafatiran wanaagsan maqaal ku saabsan TaskSchedulers blogka Microsoft.

Si loo saxo wax kasta oo la xidhiidha Hawlaha, Visual Studio wuxuu leeyahay daaqad Hawlaha. Daaqaddan waxaad ku arki kartaa sida ay hadda tahay hawsha oo aad u booddaa xariiqda koodka ee hadda fulinaysa.

NET: Aaladaha loogu talagalay in lagu shaqeeyo isku-dhufashada iyo asynchrony. Qaybta 1

PLinq iyo fasalka barbar socda

Marka lagu daro Hawlaha iyo wax kasta oo iyaga ku saabsan, waxaa jira laba qalab oo kale oo xiiso leh oo ku jira NET: PLinq (Linq2Parallel) iyo fasalka Parallel. Midka ugu horreeya wuxuu ballanqaadayaa fulinta isbarbardhigga dhammaan hawlgallada Linq ee dunta badan. Tirada dunta waxaa lagu habeyn karaa iyadoo la adeegsanayo habka fidinta WithDegreeOfParallelism. Nasiib darro, inta badan PLinq qaabkeeda caadiga ah ma hayso macluumaad ku filan oo ku saabsan macluumaadka gudaha ee isha xogtaada si ay u bixiso faa'iido xawaare weyn leh, dhanka kale, qiimaha iskudayga waa mid aad u hooseeya: kaliya waxaad u baahan tahay inaad wacdo habka AsParallel ka hor silsiladda hababka Linq iyo socodsiinta imtixaanada waxqabadka. Waxaa intaa dheer, waa suurtagal in loo gudbiyo PLinq macluumaad dheeraad ah oo ku saabsan dabeecadda isha xogtaada iyadoo la adeegsanayo habka Qaybaha. Wax badan ayaad akhrin kartaa halkan и halkan.

Fasalka isbar-bar yaacaya wuxuu bixiyaa habab lagu cel-celiyo iyada oo loo marayo ururinta Foreach oo isbarbar socda, fulinta a For loop, iyo fulinta ergo badan oo isbarbar socda. Fulinta dunta hadda socota waa la joojin doonaa ilaa xisaabinta la dhammeeyo. Tirada dunta waxaa lagu habeyn karaa iyadoo loo gudbiyo ParallelOptions sidii dooddii ugu dambeysay. Waxa kale oo aad cayimi kartaa TaskScheduler iyo CancelationToken adiga oo isticmaalaya xulashooyinka.

natiijooyinka

Markii aan bilaabay qoritaanka maqaalkan anigoo ka duulaya agabka warbixintayda iyo xogtii aan ururiyay intii aan shaqada ku jiray ka dib, maan fileyn inay wax badan ka heli doonaan. Haddaba, marka tifaftiraha qoraalka aan maqaalkan ku qorayo uu si badheedh ah ii sheego in bogga 15 uu baxay, waxaan soo koobayaa natiijada ku meel gaadhka ah. Khiyaamooyinka kale, API-yada, aaladaha muuqaalka iyo dabinnada ayaa lagu dabooli doonaa maqaalka soo socda.

Gabagabo:

  • Waxaad u baahan tahay inaad ogaato qalabka lagu shaqeeyo dunta, asynchrony iyo isbarbardhigga si aad u isticmaasho agabka PC-yada casriga ah.
  • NET waxay leedahay qalabyo badan oo kala duwan ujeedooyinkan
  • Dhammaantood ma wada muuqan hal mar, sidaas darteed waxaad inta badan heli kartaa kuwa dhaxalka ah, si kastaba ha ahaatee, waxaa jira siyaabo lagu beddelo API-yadii hore iyada oo aan dadaal badan lahayn.
  • Ku shaqaynta dunta .NET waxa matala fasalada Thread iyo ThreadPool
  • The Thread.Abort, Thread.Interrupt, iyo Win32 API Joojinta Hababka xadhiggu waa khatar oo laguma talinayo in la isticmaalo. Taa beddelkeeda, way fiicantahay in la isticmaalo habka CancelationToken
  • Socodku waa kheyraad qiimo leh sahaydiisuna waa xaddidan tahay. Xaaladaha ay duntu ku mashquulsan tahay sugitaanka dhacdooyinka waa in laga fogaadaa. Tan waxaa ku habboon in la isticmaalo fasalka TaskCompletionSource
  • Aaladaha .NET ee ugu awooda badan uguna horumarsan ee lagu shaqaynayo isbarbar yaaca iyo asnchrony waa Hawsha.
  • Hawl-wadeenada c# async/sugidda waxay hirgeliyaan fikradda sugitaanka aan xannibin
  • Waxaad koontarooli kartaa qaybinta Hawlaha dunta oo dhan adiga oo isticmaalaya xiisado ka soo jeeda TaskScheduler
  • Qaab dhismeedka ValueTask wuxuu faa'iido u yeelan karaa hagaajinta waddooyinka kulul iyo xusuusta-taraafikada
  • Visual Studio's Tasks and Threads daaqadaha ayaa bixiya macluumaad badan oo faa'iido leh si loo tirtiro koodka-threaded-ka badan ama asynchronous
  • PLinq waa qalab fiican, laakiin waxaa laga yaabaa inaysan haysan macluumaad ku filan oo ku saabsan isha xogtaada, laakiin tan waxaa lagu hagaajin karaa iyadoo la adeegsanayo habka qaybinta
  • In la sii wado ...

Source: www.habr.com

Add a comment