.NET: Amathuluzi okusebenza nge-multithreading ne-asynchrony. Ingxenye 1

Ngishicilela i-athikili yangempela ku-Habr, okuhunyushwe kwayo okuthunyelwe enkampanini iposi lebhulogi.

Isidingo sokwenza okuthile ngokuvumelanayo, ngaphandle kokulinda umphumela lapha futhi manje, noma ukuhlukanisa umsebenzi omkhulu phakathi kwamayunithi amaningana awenza, sasikhona ngaphambi kokufika kwamakhompyutha. Ngokufika kwabo, lesi sidingo saba yinto ebonakalayo kakhulu. Manje, ngo-2019, ngibhala lesi sihloko kwikhompyutha ephathekayo ene-8-core Intel Core processor, lapho izinqubo ezingaphezu kwekhulu zisebenza ngokufana, kanye nemicu eyengeziwe. Eduze, kunefoni ethe ukonakala, ethengwe eminyakeni embalwa edlule, ine-8-core processor ebhodini. Izinsiza ezinezihloko zigcwele izindatshana namavidiyo lapho ababhali bazo bethakasela khona ama-smartphones aphambili alo nyaka anamaphrosesa angu-16-core. I-MS Azure ihlinzeka ngomshini obonakalayo onephrosesa engu-20 kanye ne-128 TB RAM ngaphansi kuka-$2/ihora. Ngeshwa, akunakwenzeka ukukhipha ubuningi futhi usebenzise la mandla ngaphandle kokukwazi ukuphatha ukusebenzisana kwemicu.

I-terminology

Inqubo - Into ye-OS, indawo yekheli engayodwa, iqukethe imicu.
Uchungechunge - into ye-OS, iyunithi encane yokubulawa, ingxenye yenqubo, imicu yabelana ngenkumbulo nezinye izinsiza phakathi kwenqubo.
Ukwenza imisebenzi eminingi - Impahla ye-OS, ikhono lokusebenzisa izinqubo eziningana ngasikhathi sinye
I-Multi-core - Isakhiwo seprosesa, ikhono lokusebenzisa ama-cores amaningana ekucutshungulweni kwedatha
Ukucubungula okuningi - impahla yekhompiyutha, ikhono lokusebenza ngesikhathi esisodwa namaphrosesa amaningana ngokomzimba
Multithreading - isici senqubo, ikhono lokusabalalisa ukucutshungulwa kwedatha phakathi kwemicu embalwa.
Ukufana - ukwenza izenzo eziningana ngokomzimba ngesikhathi esisodwa ngeyunithi ngayinye yesikhathi
I-Asynchrony - ukwenziwa komsebenzi ngaphandle kokulinda ukuqedwa kwalokhu kucutshungulwa kungacutshungulwa kamuva.

Isingathekiso

Akuzona zonke izincazelo ezinhle futhi ezinye zidinga incazelo eyengeziwe, ngakho-ke ngizofaka isingathekiso mayelana nokupheka kwasekuseni kugama lamagama ethulwe ngokusemthethweni. Ukupheka ukudla kwasekuseni kulesi singathekiso kuyinqubo.

Ngenkathi ngilungisa isidlo sasekuseni ekuseni mina (CPU) ngiza ekhishini (Ikhompyutha). nginezandla ezi-2 (cores). Kunenombolo yemishini ekhishini (IO): ihhavini, iketela, i-toaster, isiqandisi. Ngivule igas ngifake i-frying pan bese ngithela amafutha kuyo ngingalindi ukuthi ishise (ngokulinganayo, Ukungavimbeli-IO-Linda), ngikhipha amaqanda esiqandisini ngiwahlephule epuletini, bese ngiwashaya ngesandla esisodwa (Uchungechunge#1), futhi okwesibili (Uchungechunge#2) ephethe ipuleti (Insiza Ehlanganyelwe). Manje ngithanda ukuvula igedlela, kodwa anginazo izandla ezanele (Indlala Yentambo) Phakathi nalesi sikhathi, i-pan yokuthosa iyashisa (Ukucubungula umphumela) lapho ngithela lokho engikushayile. Ngithathe iketela ngilivule ngibuke amanzi abilayo ngalo.Ukuvimba-IO-Linda), nakuba ngalesi sikhathi wayengageza ipuleti lapho eshaya khona i-omelet.

Ngipheke i-omelet ngisebenzisa izandla ezi-2 kuphela, futhi anginakho okwengeziwe, kodwa ngesikhathi esifanayo, ngesikhathi sokushaya i-omelet, kwenziwa imisebenzi emi-3 ngesikhathi esisodwa: ukushaya i-omelette, ukubamba ipuleti, ukushisa ipani lokuthosa. . I-CPU iyingxenye eshesha kakhulu yekhompuyutha, i-IO iyona evamise ukuthi yonke into ibambezeleke, ngakho-ke imvamisa isisombululo esisebenzayo siwukuthatha i-CPU ngokuthile ngenkathi uthola idatha evela ku-IO.

Iqhubeka isingathekiso:

  • Uma ngesikhathi sokulungiselela i-omelet, ngizophinde ngizame ukushintsha izingubo, lokhu kungaba isibonelo se-multitasking. I-nuance ebalulekile: amakhompyutha angcono kakhulu kulokhu kunabantu.
  • Ikhishi elinabapheki abaningana, isibonelo endaweni yokudlela - ikhompyutha enezingqikithi eziningi.
  • Izindawo zokudlela eziningi enkundleni yokudla esikhungweni sezitolo - isikhungo sedatha

.NET Amathuluzi

I-.NET inhle ekusebenzeni ngezintambo, njengezinye izinto eziningi. Ngenguqulo entsha ngayinye, yethula amathuluzi amaningi amasha okusebenza nawo, izendlalelo ezintsha zokukhipha phezu kwemicu ye-OS. Lapho besebenza nokwakhiwa kokukhipha, abathuthukisi bohlaka basebenzisa indlela eshiya ithuba, lapho besebenzisa i-abstraction ephezulu, ukwehla izinga elilodwa noma ngaphezulu ngezansi. Ngokuvamile lokhu akudingekile, empeleni kuvula umnyango wokuzidubula ezinyaweni ngesibhamu, kodwa ngezinye izikhathi, ezimweni ezingavamile, kungase kube ukuphela kwendlela yokuxazulula inkinga engaxazululeki ezingeni lamanje lokukhipha. .

Ngamathuluzi, ngisho kokubili i-application programming interfaces (APIs) ehlinzekwa uhlaka namaphakheji ezinkampani zangaphandle, kanye nezixazululo zesofthiwe eziphelele ezenza kube lula ukusesha kwanoma yiziphi izinkinga ezihlobene nekhodi enezintambo eziningi.

Ukuqala uchungechunge

Ikilasi le-Thread yikilasi eliyisisekelo kakhulu ku-.NET lokusebenza ngemicu. Umakhi wamukela omunye wezithunywa ezimbili:

  • I-ThreadStart - Awekho amapharamitha
  • I-ParametrizedThreadStart - enepharamitha eyodwa yohlobo lwento.

Isithunywa sizosetshenziswa ochungechungeni olusanda kwakhiwa ngemva kokubiza indlela yokuQala Uma isithunywa sohlobo lwe-ParametrizedThreadStart sidluliselwe kumakhi, khona-ke into kufanele idluliselwe endleleni yokuqala. Le nqubo iyadingeka ukuze kudluliselwe noma yiluphi ulwazi lwendawo ekusakazweni. Kuyaphawuleka ukuthi ukwakha intambo kuwumsebenzi obizayo, futhi intambo ngokwayo iyinto esindayo, okungenani ngoba yabela inkumbulo engu-1MB esitakini futhi idinga ukusebenzisana ne-OS API.

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

Isigaba se-ThreadPool simele umqondo wechibi. Ku-.NET, i-thread pool iyingxenye yobunjiniyela, futhi abathuthukisi be-Microsoft benze umzamo omkhulu wokuqinisekisa ukuthi isebenza kahle kakhulu ezimweni eziningi ezihlukahlukene.

Umqondo ojwayelekile:

Kusukela ngesikhathi uhlelo luqala, ludala imicu eminingana egciniwe ngemuva futhi lunikeze ikhono lokulusebenzisa. Uma izintambo zisetshenziswa njalo futhi ngamanani amakhulu, ichibi liyakhula ukuze lihlangabezane nezidingo zofonayo. Uma ingekho imicu yamahhala echibini ngesikhathi esifanele, izolinda ukuthi intambo eyodwa ibuye, noma idale entsha. Lokhu kulandela ukuthi i-thread pool yinhle ezenzweni ezithile zesikhashana futhi ayifaneleki kahle imisebenzi esebenza njengamasevisi kukho konke ukusebenza kohlelo lokusebenza.

Ukuze usebenzise uchungechunge olusuka ku-pool, kukhona indlela ye-QueueUserWorkItem eyamukela isithunywa sohlobo lwe-WaitCallback, esinesiginesha efana ne-ParametrizedThreadStart, futhi ipharamitha edluliselwe kuyo yenza umsebenzi ofanayo.

ThreadPool.QueueUserWorkItem(...);

Indlela ye-thread pool eyaziwa kancane, RegisterWaitForSingleObject isetshenziselwa ukuhlela imisebenzi ye-IO engavimbi. Isithunywa esidluliselwe kule ndlela sizobizwa uma i-WaitHandle idlulele endleleni "Ikhishiwe".

ThreadPool.RegisterWaitForSingleObject(...)

I-.NET inesibali sikhathi sentambo futhi ihlukile kuzibali zesikhathi ze-WinForms/WPF ngokuthi isibambi sayo sizobizwa ngentambo ethathwe echibini.

System.Threading.Timer

Kukhona futhi indlela exakile yokuthumela isithunywa ukuze sibulawe ochungechungeni olusuka echibini - indlela ye-BeginInvoke.

DelegateInstance.BeginInvoke

Ngingathanda ukuhlala kafushane emsebenzini lapho izindlela eziningi ezingenhla zingabizwa khona - CreateThread from Kernel32.dll Win32 API. Kukhona indlela, ngenxa yomshini wezindlela zangaphandle, ukubiza lo msebenzi. Ngilubone ucingo olunjalo kanye kuphela esibonelweni esibi sekhodi yefa, futhi ugqozi lombhali owenze lokhu kuseyimpicabadala kimi.

Kernel32.dll CreateThread

Ukubuka kanye nokususa iphutha Imicu

Imicu edalwe nguwe, zonke izingxenye zenkampani yangaphandle, kanye nephuli ye-NET ingabukwa efasiteleni Lemiluko le-Visual Studio. Leli windi lizobonisa ulwazi lochungechunge kuphela uma uhlelo lokusebenza lungaphansi kokulungisa iphutha futhi likumodi ye-Break. Lapha ungakwazi ukubuka kalula amagama esitaki nezinto ezibalulekile zochungechunge ngalunye, futhi ushintshe ukulungisa iphutha kuchungechunge oluthile. Usebenzisa isici Esibalulekile Sekilasi Lochungechunge, ungasetha okubalulekile kochungechunge, i-OC ne-CLR abazoyibona njengesincomo lapho behlukanisa isikhathi sokucubungula phakathi kwezintambo.

.NET: Amathuluzi okusebenza nge-multithreading ne-asynchrony. Ingxenye 1

I-Task Parallel Library

I-Task Parallel Library (TPL) yethulwe ku-.NET 4.0. Manje yizinga kanye nethuluzi eliyinhloko lokusebenza nge-asynchrony. Noma iyiphi ikhodi esebenzisa indlela endala ibhekwa njengefa. Iyunithi eyisisekelo ye-TPL yisigaba somsebenzi esivela ku-System.Threading.Tasks namespace. Umsebenzi uwukufinyeza phezu kochungechunge. Ngenguqulo entsha yolimi lwe-C#, sithole indlela enhle yokusebenza neMisebenzi - i-async/await opharetha. Le mibono yenza ukuthi kube nokwenzeka ukubhala ikhodi ye-asynchronous njengokungathi ilula futhi ivumelanisa, lokhu kwenza ukuthi ngisho nabantu abanokuqonda okuncane kokusebenza kwangaphakathi kwezintambo babhale izinhlelo zokusebenza ezizisebenzisayo, izinhlelo zokusebenza ezingakhiqizi lapho zenza imisebenzi emide. Ukusebenzisa i-async/await kuyisihloko sendatshana eyodwa noma ezimbalwa, kodwa ngizozama ukuthola umongo wayo ngemisho embalwa:

  • I-async iyisilungisi sendlela ebuyisela Umsebenzi noma ubuze
  • futhi i-wait ingu-opharetha ongavimbi Umsebenzi olindile.

Nakulokhu: u-opharetha olindile, esimweni esivamile (kukhona okuhlukile), uzokhipha intambo yamanje yokubulawa ngokuqhubekayo, futhi lapho Umsebenzi uqeda ukukhishwa kwawo, kanye nentambo (empeleni, kungaba ngokunembile ukusho umongo. , kodwa okuningi ngalokho kamuva) izoqhubeka nokusebenzisa indlela ngokuqhubekayo. Ngaphakathi kwe-.NET, le nqubo isetshenziswa ngendlela efanayo ne-yield return, lapho indlela ebhaliwe iphenduka iklasi lonke, okuwumshini wombuso futhi ongenziwa ngezingcezu ezihlukene kuye ngalezi zifunda. Noma ubani onentshisekelo angabhala noma iyiphi ikhodi elula esebenzisa i-asynс/await, ahlanganise futhi abuke umhlangano esebenzisa i-JetBrains dotPeek ene-Compiler Generated Code enikwe amandla.

Ake sibheke izinketho zokuqalisa nokusebenzisa i-Task. Esibonelweni sekhodi esingezansi, sakha umsebenzi omusha ongenzi lutho oluwusizo (Uchungechunge.Lala(10000)), kodwa empilweni yangempela lokhu kufanele kube umsebenzi onzima we-CPU.

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
}

Umsebenzi udalwa ngenani lezinketho:

  • I-LongRunning iwuphawu lokuthi umsebenzi ngeke uqedwe ngokushesha, okusho ukuthi kungase kudingeke ukuthi ucabangele ukungathathi intambo echibini, kodwa udale ehlukile yalo Msebenzi ukuze ungalimazi abanye.
  • I-AtachedToParent - Imisebenzi ingahlelwa ngokulandelana kwezigaba. Uma le nketho isetshenzisiwe, khona-ke Umsebenzi ungase ube sesimweni lapho wona usuqedile futhi ulinde ukubulawa kwezingane zawo.
  • I-PreferFairness - kusho ukuthi kungaba ngcono ukwenza Imisebenzi ethunyelwe ngaphambi kwesikhathi ngaphambi kwaleyo ethunyelwe kamuva. Kodwa lokhu kumane kuyizincomo futhi imiphumela ayiqinisekisiwe.

Ipharamitha yesibili edluliselwe endleleni ithi CancellationToken. Ukuze uphathe kahle ukukhanselwa komsebenzi ngemva kokuthi usuqalile, ikhodi esetshenziswayo kufanele igcwaliswe ngamasheke wesimo Sophawu Lokukhansela. Uma kungekho ukuhlola, indlela yokukhansela ebizwa ngokuthi CancellationTokenSource izokwazi ukumisa ukwenziwa Komsebenzi kuphela ngaphambi kokuthi uqale.

Ipharamitha yokugcina iyisihleli sento yohlobo lwe-TaskScheduler. Lesi sigaba kanye nenzalo yaso sidizayinelwe ukulawula amasu okusabalalisa Imisebenzi kuchungechunge ngokuzenzakalela, Umsebenzi uzokwenziwa ngochungechunge olungahleliwe olusuka echibini.

I-opharetha yokulinda isetshenziswa ku-Task edaliwe, okusho ukuthi ikhodi ebhalwe ngemva kwayo, uma ikhona, izokwenziwa kumongo ofanayo (ngokuvamile lokhu kusho kuntambo efanayo) njengekhodi ngaphambi kokulinda.

Indlela imakwe njenge-async void, okusho ukuthi ingasebenzisa opharetha abalindile, kodwa ikhodi yokushaya ngeke ikwazi ukulinda ukwenziwa. Uma isici esinjalo sidingeka, khona-ke indlela kufanele ibuyisele Umsebenzi. Izindlela ezimakwe njenge-async void zivame kakhulu: njengomthetho, lezi izibambi zomcimbi noma ezinye izindlela ezisebenza emlilweni futhi zikhohlwe isimiso. Uma ungagcini nje ngokunikeza ithuba lokulinda kuze kube sekupheleni kokubulawa, kodwa futhi ubuyisele umphumela, khona-ke udinga ukusebenzisa i-Task.

Emsebenzini obuyisiwe indlela ye-StartNew, kanye nakunoma iyiphi enye, ungashayela indlela ye-ConfigureAwait ngepharamitha engamanga, bese ukwenza ngemva kokulinda kuzoqhubeka hhayi emongweni othwetshuliwe, kodwa kokunye okungahleliwe. Lokhu kufanele kwenziwe njalo lapho umongo wokusebenzisa ungabalulekile kukhodi ngemva kokulinda. Lesi futhi isincomo esivela ku-MS lapho ubhala ikhodi ezolethwa ipakishwe emtatsheni wezincwadi.

Ake sigxile kancane ekutheni ungalinda kanjani ukuqedwa komsebenzi. Ngezansi kunesibonelo sekhodi, namazwana lapho okulindelekile kwenziwa kahle ngokwemibandela futhi uma kwenziwa kabi ngokwemibandela.

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
}

Esibonelweni sokuqala, silinda ukuthi uMsebenzi uqedele ngaphandle kokuvimba intambo yokubiza sizobuyela ekucubunguleni umphumela kuphela lapho usuvele ukhona;

Okukhethwa kukho kwesibili, sivimba intambo yokubiza kuze kube yilapho kubalwa umphumela wendlela. Lokhu kubi hhayi nje ngoba sibambe intambo, insiza ebaluleke kangaka yohlelo, ngokungenzi lutho okulula, kodwa futhi ngoba uma ikhodi yendlela esiyibizayo iqukethe ukulinda, futhi umongo wokuvumelanisa udinga ukubuyela kuntambo yokubiza ngemuva linda, khona-ke sizothola i-deadlock : Intambo yokubiza ilinda umphumela wendlela ye-asynchronous ukuba ibalwe, indlela ye-asynchronous izama ize ukuqhubeka nokusebenza kwayo kuntambo yokubiza.

Okunye okungalungile kwale ndlela ukuphatha amaphutha okuyinkimbinkimbi. Iqiniso liwukuthi amaphutha kukhodi ye-asynchronous uma usebenzisa i-async/await kulula kakhulu ukusingathwa - aziphatha ngendlela efanayo nokuthi ikhodi iyavumelana. Nakuba uma sisebenzisa i-synchronous wait exorcism ku-Task, okuhlukile kwasekuqaleni kuphenduka i-AggregateException, i.e. Ukuze uphathe okuhlukile, kuzodingeka uhlole uhlobo lwe-InnerException bese ubhala ukuthi uma chain ngokwakho ngaphakathi kwebhulokhi yokubamba eyodwa noma usebenzise okubambekayo lapho wakha, esikhundleni sochungechunge lwamabhulokhi okubamba ajwayeleke kakhulu emhlabeni we-C#.

Izibonelo zesithathu nesokugcina nazo zimakwe njengezibi ngesizathu esifanayo futhi ziqukethe zonke izinkinga ezifanayo.

Izindlela ze-WhenAny kanye nethi WhenAll zilungele kakhulu ukulinda iqembu Lemisebenzi; zigoqa iqoqo Lemisebenzi ibe yinto eyodwa, ezoqhumisa noma ngabe uMsebenzi weqembu uqala ukwenziwa, noma uma wonke eseqedile ukwenza.

Ukumisa imicu

Ngenxa yezizathu ezihlukahlukene, kungase kudingeke ukuthi kumiswe ukugeleza ngemva kokuba sekuqalile. Ziningi izindlela zokwenza lokhu. Isigaba se-Thread sinezindlela ezimbili eziqanjwe ngokufanelekile: Khipha isisu и Phazamisa. Eyokuqala ayinconywa kakhulu ukuthi isetshenziswe, ngoba ngemva kokuyibiza nganoma isiphi isikhathi esingahleliwe, ngesikhathi sokucutshungulwa kwanoma yimuphi umyalo, okuhlukile kuzokwenziwa I-ThreadAbortedException. Awulindele lokho okuhlukile ukuthi kwenziwe lapho kukhushulwa noma yikuphi okuguquguqukayo okuphelele, akunjalo? Futhi uma usebenzisa le ndlela, lesi isimo sangempela kakhulu. Uma udinga ukuvimbela i-CLR ekukhiqizeni okuhlukile esigabeni esithile sekhodi, ungayisonga ngezingcingo. Thread.BeginCriticalRegion, Thread.EndCriticalRegion. Noma iyiphi ikhodi ebhalwe kubhlokhi ekugcineni isongwe ngezingcingo ezinjalo. Ngenxa yalesi sizathu, ekujuleni kwekhodi yohlaka ungathola amabhlogo ngokuzama okungenalutho, kodwa hhayi okungenalutho ekugcineni. I-Microsoft idikibalisa le ndlela kangangokuthi ayizange iyifake ku-.net core.

Indlela yokuphazamisa isebenza ngokuqagela kakhulu. Ingaphazamisa uchungechunge ngokuhlukile I-ThreadInterruptedException kuphela ngalezo zikhathi lapho intambo isesimweni sokulinda. Ingena kulesi simo ngenkathi ilenga ngenkathi ilinde i-WaitHandle, ikhiya, noma ngemva kokubiza i-Thread.Sleep.

Zombili izinketho ezichazwe ngenhla zimbi ngenxa yokungabikezeli kwazo. Isixazululo ukusebenzisa isakhiwo CancellationToken kanye nekilasi CancellationTokenSource. Iphuzu liwukuthi: isibonelo sekilasi le-CancellationTokenSource siyadalwa futhi ngumnikazi walo kuphela ongamisa ukusebenza ngokubiza indlela. Khansela. I-CancellationToken kuphela edluliswa emsebenzini ngokwawo. Abanikazi be-CancellationToken abakwazi ukukhansela ukusebenza ngokwabo, kodwa bangahlola kuphela ukuthi umsebenzi ukhanseliwe yini. Kukhona indawo ye-Boolean yalokhu UkukhanselaKuceliwe kanye nendlela I-ThrowIfCancelRequested. Lesi sakamuva sizokhipha okuhlukile I-TaskCancelledException uma indlela yokukhansela ibizwe esibonelweni seCancellationToken sipherithwa. Futhi lena indlela engincoma ukuyisebenzisa. Lokhu wukuthuthukisa kunezinketho zangaphambilini ngokuthola ukulawula okugcwele kokuthi kunini lapho umsebenzi ohlukile ongayekiswa khona.

Inketho enonya kakhulu yokumisa intambo ukushayela umsebenzi weWin32 API TerminateThread. Ukuziphatha kwe-CLR ngemva kokubiza lo msebenzi kungase kungabonakali. Ku-MSDN kubhalwe okulandelayo mayelana nalo msebenzi: “I-TerminateThread iwumsebenzi oyingozi okufanele usetshenziswe ezimweni ezimbi kakhulu. “

Ukuguqula i-legacy API ibe iTask Based kusetshenziswa indlela ye-FrockAsync

Uma unenhlanhla yokusebenza kuphrojekthi eyaqalwa ngemuva kokuthi Imisebenzi yethulwe futhi yayeka ukubangela ukwethuka okuthulile konjiniyela abaningi, lapho-ke ngeke kudingeke ubhekane nama-API amaningi amadala, womabili awezinkampani zangaphandle kanye nalawo ithimba lakho. uye wahlukumeza esikhathini esidlule. Ngenhlanhla, ithimba le-.NET Framework lasinakekela, nakuba mhlawumbe inhloso bekuwukuzinakekela. Noma kunjalo, i-.NET inamathuluzi amaningana okuguqula ngokungenabuhlungu ikhodi ebhalwe ngezindlela zakudala zokuhlela ezingavumelanisi ukuya kwentsha. Enye yazo indlela ye-FromAsync ye-TaskFactory. Esibonelweni sekhodi esingezansi, ngigoqa izindlela zakudala ze-async zekilasi leWebRequest ku-Task usebenzisa le ndlela.

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

Lesi isibonelo nje futhi ngeke kwenzeke ukuthi wenze lokhu ngezinhlobo ezakhelwe ngaphakathi, kodwa noma iyiphi iphrojekthi endala imane igcwele izindlela ze-BeginDoSomething ezibuyisela i-IAsyncResult kanye nezindlela ze-EndDoSomething eziyitholayo.

Guqula i-legacy API ibe Task Based usebenzisa ikilasi le-TaskCompletionSource

Elinye ithuluzi elibalulekile okufanele licatshangelwe yikilasi I-TaskCompletionSource. Mayelana nemisebenzi, inhloso kanye nesimiso sokusebenza, kungase kufane ngandlela thize indlela yeRegisterWaitForSingleObject yekilasi le-ThreadPool, engibhale ngayo ngenhla. Usebenzisa leli klasi, ungakwazi ukugoqa kalula futhi kalula ama-API amadala asynchronous kokuthi Imisebenzi.

Uzosho ukuthi sengivele ngikhulume ngendlela ye-FromAsync yekilasi le-TaskFactory ehloselwe lezi zinhloso. Lapha kuzodingeka sikhumbule wonke umlando wokuthuthukiswa kwamamodeli asynchronous ku-.net iMicrosoft enikeze ngayo eminyakeni eyi-15 edlule: ngaphambi kwe-Task-Based Asynchronous Pattern (TAP), kwakukhona i-Asynchronous Programming Pattern (APP), okuyinto yayimayelana nezindlela QalaYenza okuthize kuyabuya IAsyncResult kanye nezindlela UkuphelaI-DoSomething eyamukelayo kanye nefa lale minyaka indlela ye-FromAsync ilungile, kodwa ngokuhamba kwesikhathi, yathathelwa indawo Iphethini Ye-Asynchronous Yomcimbi (I-EAP), obekucatshangwa ukuthi umcimbi uzophakanyiswa lapho ukusebenza kwe-asynchronous kuqedwa.

I-TaskCompletionSource ilungele ukugoqa Imisebenzi nama-API ayigugu akhelwe eduze kwemodeli yomcimbi. Ingqikithi yomsebenzi wayo imi kanje: into yalesi sigaba inempahla yomphakathi yohlobo lwe-Task, isimo sayo esingalawulwa ngokusebenzisa i-SetResult, SetException, njll. izindlela zekilasi le-TaskCompletionSource. Ezindaweni lapho u-opharetha olindile asetshenziswe kulo Msebenzi, uzokwenziwa noma wehluleke ngaphandle kuye ngendlela esetshenziswe ku-TaskCompletionSource. Uma namanje kungacacile, ake sibheke lesi sibonelo sekhodi, lapho enye i-EAP API endala isongwe ku-Task kusetshenziswa i-TaskCompletionSource: uma umcimbi uvutha, Umsebenzi uzodluliselwa esimweni Sokuqedwa, kanye nendlela esebenzise u-opharetha olindile. kulo Msebenzi uzoqala kabusha ukusebenza ngemuva kokuthola into umphumela.

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

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

    result completionSource.Task;
}

Amathiphu namaqhinga we-TaskCompletionSource

Ukusonga ama-API amadala akukhona konke okungenziwa kusetshenziswa i-TaskCompletionSource. Ukusebenzisa leli klasi kuvula ithuba elithokozisayo lokuklama ama-API ahlukahlukene ku-Tasks engathathi imicu. Futhi ukusakaza, njengoba sikhumbula, kuyinsiza ebizayo futhi inombolo yabo inqunyelwe (ikakhulukazi ngenani le-RAM). Lo mkhawulo ungafinyelelwa kalula ngokwakha, isibonelo, uhlelo lokusebenza lwewebhu olulayishiwe olunomqondo webhizinisi oyinkimbinkimbi. Ake sicabangele amathuba engikhuluma ngawo lapho sisebenzisa iqhinga elifana neLong-Polling.

Ngamafuphi, ingqikithi yobuqili yilokhu: udinga ukuthola ulwazi oluvela ku-API mayelana nezenzakalo ezithile ezenzeka ohlangothini lwayo, kuyilapho i-API, ngesizathu esithile, ayikwazi ukubika umcimbi, kodwa ingabuyisela isimo kuphela. Isibonelo salokhu wonke ama-API akhelwe phezu kwe-HTTP ngaphambi kwezikhathi zeWebSocket noma lapho kwakungenakwenzeka ngesizathu esithile ukusebenzisa lobu buchwepheshe. Iklayenti lingabuza iseva ye-HTTP. Iseva ye-HTTP ayikwazi ngokwayo ukuqalisa ukuxhumana neklayenti. Isixazululo esilula ukuhlola iseva usebenzisa isibali sikhathi, kodwa lokhu kudala umthwalo owengeziwe kuseva kanye nokubambezeleka okwengeziwe ngokwesilinganiso se-TimerInterval / 2. Ukuze uzungeze lokhu, kwasungulwa iqhinga elibizwa nge-Long Polling, elihilela ukubambezeleka kwempendulo evela. iseva kuze kuphele isikhathi sokuvala noma kwenzeke umcimbi. Uma umcimbi wenzekile, bese uyacutshungulwa, uma kungenjalo, isicelo sithunyelwa futhi.

while(!eventOccures && !timeoutExceeded)  {

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

Kodwa isixazululo esinjalo sizobonakala sisibi ngokushesha nje lapho inani lamaklayenti alinde umcimbi likhula, ngoba ... Iklayenti ngalinye elinjalo lithatha uchungechunge lonke lilindele umcimbi. Yebo, futhi sithola ukulibaziseka okwengeziwe kwe-1ms lapho umcimbi uqalwa, ngokuvamile lokhu akubalulekile, kodwa kungani ukwenza isofthiwe ibe yimbi kakhulu kunalokho engaba yikho? Uma sisusa i-Thread.Sleep(1), sizobe silayisha ize i-processor core eyodwa 100% engenzi lutho, sizungezisa umjikelezo ongenamsebenzi. Ngokusebenzisa i-TaskCompletionSource ungenza kabusha le khodi kalula futhi uxazulule zonke izinkinga ezishiwo ngenhla:

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);
    }
}

Le khodi ayilungile ukukhiqizwa, kodwa iyidemo nje. Ukuze uyisebenzise ezimweni zangempela, udinga futhi, okungenani, ukuphatha isimo lapho umlayezo ufika ngesikhathi lapho kungekho muntu owulindele: kulokhu, indlela ye-AsseptMessageAsync kufanele ibuyisele Umsebenzi osuvele uqediwe. Uma leli kuyicala elivame kakhulu, ungacabanga ngokusebenzisa i-ValueTask.

Uma sithola isicelo somlayezo, sidala futhi sibeke i-TaskCompletionSource kusichazamazwi, bese silinda okwenzeka kuqala: isikhawu sesikhathi esishiwo siphelelwa yisikhathi noma umlayezo wamukelwe.

ValueTask: kungani futhi kanjani

Ama-opharetha we-async/await, njenge-opharetha yokubuyisela isivuno, akhiqiza umshini wombuso kusuka endleleni, futhi lokhu kungukwakhiwa kwento entsha, cishe engabalulekile ngaso sonke isikhathi, kodwa ezimweni ezingavamile ingadala inkinga. Leli cala lingase libe indlela ebizwa ngokuthi ngokuvamile ngempela, sikhuluma ngamashumi namakhulu ezinkulungwane zezingcingo ngomzuzwana. Uma indlela enjalo ibhalwe ngendlela yokuthi ezimweni eziningi ibuyisela umphumela ngokudlula zonke izindlela zokulinda, khona-ke i-NET inikeza ithuluzi lokuthuthukisa lokhu - isakhiwo se-ValueTask. Ukuze sikwenze kucace, ake sibheke isibonelo sokusetshenziswa kwayo: kukhona inqolobane esiya kuyo kaningi. Kunamanani athile kuwo bese sivele siwabuyisele; Ngifuna ukwenza lokhu kokugcina ngokulinganayo, okusho ukuthi yonke indlela iphenduka i-asynchronous. Ngakho, indlela esobala yokubhala indlela imi kanje:

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

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

Ngenxa yesifiso sokuthuthukisa kancane, kanye nokwesaba okuncane kokuthi uRoslyn uzokhiqiza ini lapho ehlanganisa le khodi, ungaphinda ubhale lesi sibonelo ngale ndlela elandelayo:

public Task<string> GetById(int id) {

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

Ngempela, ikhambi elilungile kulokhu kungaba ukuthuthukisa indlela eshisayo, okungukuthi, ukuthola inani elivela kusichazamazwi ngaphandle kokwabiwa okungadingekile nokulayisha ku-GC, kuyilapho kulezo zimo ezingavamile lapho sisadinga ukuya ku-IO ukuthola idatha. , yonke into izohlala iyi-plus/minus indlela yakudala:

public ValueTask<string> GetById(int id) {

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

Ake sibhekisise lesi siqeshana sekhodi: uma kukhona inani kunqolobane, sakha isakhiwo, ngaphandle kwalokho umsebenzi wangempela uzosongwa ngendlela enenjongo. Ikhodi yokushaya ayinandaba ukuthi iyiphi indlela le khodi esetshenziswe kuyo: I-ValueTask, ngokombono we-C# ye-syntax, izoziphatha ngendlela efanayo Njengomsebenzi ovamile kulesi simo.

Ama-TaskSchedulers: ukuphatha amasu okuqalisa umsebenzi

I-API elandelayo engingathanda ukuyicabangela yiklasi I-TaskScheduler kanye nokuphuma kwayo. Sengikushilo ngenhla ukuthi i-TPL inamandla okuphatha amasu okusabalalisa Imisebenzi kuyo yonke imicu. Amasu anjalo achazwa enzalweni yesigaba se-TaskScheduler. Cishe noma yiliphi isu ongase ulidinge lingatholakala kulabhulali. I-ParallelExtensionsExtras, ithuthukiswe yi-Microsoft, kodwa hhayi ingxenye ye-.NET, kodwa ihlinzekwa njengephakheji le-Nuget. Ake sibheke kafushane ezinye zazo:

  • I-CurrentThreadTaskScheduler - yenza Imisebenzi kuchungechunge lwamanje
  • LimitedConcurrencyLevelTaskScheduler - ikhawulela inani leMisebenzi eyenziwe ngasikhathi sinye ngepharamitha N, eyamukelwa kumakhi
  • I-OrderedTaskScheduler — ichazwa ngokuthi LimitedConcurrencyLevelTaskScheduler(1), ngakho imisebenzi izokwenziwa ngokulandelana.
  • I-WorkStealingTaskScheduler - izisetshenziswa umsebenzi-ukweba indlela yokusabalalisa umsebenzi. Empeleni iyi-ThreadPool ehlukile. Ixazulula inkinga yokuthi ku-.NET ThreadPool iyikilasi elimile, elilodwa lazo zonke izinhlelo zokusebenza, okusho ukuthi ukugcwala kwayo noma ukusetshenziswa okungalungile engxenyeni eyodwa yohlelo kungaholela emiphumeleni engemihle kwenye. Ngaphezu kwalokho, kunzima kakhulu ukuqonda imbangela yalokhu kukhubazeka. Lokho. Kungase kube nesidingo sokusebenzisa ama-WorkStealingTaskScheduler ahlukene ezingxenyeni zohlelo lapho ukusetshenziswa kwe-ThreadPool kungase kube nolaka futhi kungabikezeli.
  • I-QueuedTaskScheduler - ikuvumela ukuthi wenze imisebenzi ngokuya ngemithetho yomugqa obalulekile
  • I-ThreadPerTaskScheduler — kwakha umucu ohlukile womsebenzi ngamunye owenziwa kuwo. Kungaba usizo emisebenzini ethatha isikhathi eside ngokungalindelekile ukuthi iqedwe.

Kukhona okuhle okuningiliziwe indatshana mayelana ne-TaskSchedulers kubhulogi le-microsoft.

Ukuze kube lula ukulungisa iphutha layo yonke into ehlobene Nemisebenzi, I-Visual Studio inewindi Lemisebenzi. Kuleli windi ungabona isimo samanje somsebenzi bese ugxumela kulayini wekhodi owenzayo njengamanje.

.NET: Amathuluzi okusebenza nge-multithreading ne-asynchrony. Ingxenye 1

I-PLinq kanye ne-Parallel class

Ngaphezu kweMisebenzi nakho konke okushiwo ngayo, kunamathuluzi amabili athakazelisa kakhulu ku-.NET: I-PLinq (Linq2Parallel) kanye nekilasi le-Parallel. Esokuqala sithembisa ukuqaliswa okufanayo kwayo yonke imisebenzi ye-Linq emicu eminingi. Inombolo yochungechunge ingalungiselelwa kusetshenziswa indlela yesandiso ye-WithDegreeOfParallelism. Ngeshwa, imvamisa i-PLinq kwimodi yayo ezenzakalelayo ayinalo ulwazi olwanele mayelana nabangaphakathi bomthombo wakho wedatha ukuze unikeze inzuzo enkulu yesivinini, ngakolunye uhlangothi, izindleko zokuzama ziphansi kakhulu: udinga nje ukushayela indlela ye-AsParallel ngaphambili. uchungechunge lwezindlela ze-Linq futhi wenze izivivinyo zokusebenza. Ngaphezu kwalokho, kungenzeka ukudlulisa ulwazi olwengeziwe ku-PLinq mayelana nemvelo yomthombo wakho wedatha usebenzisa indlela Yokuhlukanisa. Ungafunda okwengeziwe lapha и lapha.

Isigaba se-Parallel static sinikeza izindlela zokuphindaphinda ngeqoqo le-Foreach ngokuhambisana, ukusebenzisa i-loop, nokusebenzisa izithunywa eziningi ku-Invoke efanayo. Ukwenziwa kochungechunge lwamanje kuzomiswa kuze kuqedwe izibalo. Inombolo yochungechunge ingalungiselelwa ngokudlula i-ParallelOptions njengengxabano yokugcina. Ungaphinda ucacise i-TaskScheduler kanye neCancellationToken usebenzisa izinketho.

okutholakele

Lapho ngiqala ukubhala lesi sihloko ngokusekelwe ezintweni zombiko wami kanye nolwazi engangiluqoqile phakathi nomsebenzi wami ngemva kwawo, ngangingalindele ukuthi lungaba lukhulu kangako. Manje, lapho umhleli wombhalo engibhala kuwo lesi sihloko engitshela ngokuthuka ukuthi ikhasi 15 selihambile, ngizofingqa imiphumela yesikhashana. Amanye amaqhinga, ama-API, amathuluzi abonakalayo kanye nezingibe kuzohlanganiswa esihlokweni esilandelayo.

Iziphetho:

  • Udinga ukwazi amathuluzi okusebenza ngemicu, i-asynchrony kanye ne-parallelism ukuze usebenzise izinsiza zama-PC anamuhla.
  • I-.NET inamathuluzi amaningi ahlukene alezi zinhloso
  • Akuwona wonke avele ngesikhathi esisodwa, ngakho-ke ungakwazi ukuthola amafa, noma kunjalo, kunezindlela zokuguqula ama-API amadala ngaphandle komzamo omkhulu.
  • Ukusebenza ngochungechunge ku-.NET imelelwa amakilasi e-Thread ne-ThreadPool
  • Izindlela ze-Thread.Abort, Thread.Interrupt, kanye ne-Win32 API TerminateThread ziyingozi futhi azinconyelwe ukusetshenziswa. Esikhundleni salokho, kungcono ukusebenzisa indlela yeCancellationToken
  • Ukugeleza kuwumthombo obalulekile futhi ukunikezwa kwawo kulinganiselwe. Izimo lapho imicu imatasa ilinde imicimbi kufanele igwenywe. Ngalokhu kulula ukusebenzisa ikilasi le-TaskCompletionSource
  • Amathuluzi anamandla futhi athuthuke kakhulu e-NET okusebenza ngokufana ne-asynchrony Ama-Tasks.
  • Ama-opharetha we-c# async/await asebenzisa umqondo wokulinda okungavimbeli
  • Ungakwazi ukulawula ukusatshalaliswa Kwemisebenzi kuchungechunge lonke usebenzisa amakilasi asuselwa ku-TaskScheduler
  • Isakhiwo se-ValueTask singaba usizo ekuthuthukiseni izindlela ezishisayo kanye ne-memory-traffic
  • Amafasitela weMisebenzi neMiluko ye-Visual Studio ahlinzeka ngolwazi oluningi oluwusizo ekulungiseni amakhodi anemicu eminingi noma asynchronous.
  • I-PLinq iyithuluzi elipholile, kodwa ingase ingabi nolwazi olwanele mayelana nomthombo wakho wedatha, kodwa lokhu kungalungiswa kusetshenziswa indlela yokuhlukanisa.
  • Kuzoqhubeka ...

Source: www.habr.com

Engeza amazwana