NET: Awọn irinṣẹ fun ṣiṣẹ pẹlu multithreading ati asynchrony. Apa 1

Mo n ṣe atẹjade nkan atilẹba lori Habr, itumọ eyiti a fiweranṣẹ ni ile-iṣẹ naa bulọọgi.

Iwulo lati ṣe nkan ni asynchronously, laisi iduro fun abajade nibi ati bayi, tabi lati pin iṣẹ nla laarin awọn ẹya pupọ ti n ṣiṣẹ, wa ṣaaju dide ti awọn kọnputa. Pẹlu dide wọn, iwulo yii di ojulowo pupọ. Ni bayi, ni ọdun 2019, Mo n tẹ nkan yii lori kọǹpútà alágbèéká kan pẹlu ero isise Intel Core 8-core, eyiti o ju awọn ilana ọgọrun lọ ti nṣiṣẹ ni afiwe, ati paapaa awọn okun diẹ sii. Nitosi, foonu shabby die-die wa, ti o ra ni ọdun meji sẹhin, o ni ero isise 8-mojuto lori ọkọ. Awọn orisun ọrọ ti o kun fun awọn nkan ati awọn fidio nibiti awọn onkọwe ṣe fẹran awọn fonutologbolori flagship ti ọdun yii ti o ṣe ẹya awọn ilana 16-core. MS Azure n pese ẹrọ foju kan pẹlu ero isise mojuto 20 ati Ramu TB 128 fun o kere ju $2 fun wakati kan. Laanu, ko ṣee ṣe lati yọkuro ti o pọ julọ ati ijanu agbara yii laisi ni anfani lati ṣakoso ibaraenisepo ti awọn okun.

Ijinlẹ

Ilana - Ohun OS, aaye adirẹsi ti o ya sọtọ, ni awọn okun.
Opo - ohun OS kan, apa ipaniyan ti o kere julọ, apakan ti ilana kan, awọn okun pin iranti ati awọn orisun miiran laarin ara wọn laarin ilana kan.
Ṣiṣẹpọ lọpọlọpọ - Ohun-ini OS, agbara lati ṣiṣe awọn ilana pupọ ni nigbakannaa
Olona-mojuto - ohun-ini ti ero isise, agbara lati lo ọpọlọpọ awọn ohun kohun fun sisẹ data
Multiprocessing - ohun-ini ti kọnputa kan, agbara lati ṣiṣẹ nigbakanna pẹlu ọpọlọpọ awọn ilana ti ara
Multithreading - ohun-ini ti ilana kan, agbara lati pin pinpin data laarin ọpọlọpọ awọn okun.
Iparapọ - ṣiṣe awọn iṣe pupọ ni igbakanna ni akoko kan
Asynchrony - ipaniyan ti iṣẹ lai duro fun ipari ti ilana yii;

Àkàwé

Kii ṣe gbogbo awọn itumọ ni o dara ati pe diẹ ninu nilo alaye ni afikun, nitorinaa Emi yoo ṣafikun apẹrẹ kan nipa sise ounjẹ aarọ si awọn ọrọ asọye ti ipilẹṣẹ. Sise ounjẹ owurọ ni apejuwe yii jẹ ilana kan.

Lakoko ngbaradi ounjẹ owurọ ni owurọ Mo (Sipiyu) Mo wa si ibi idana (Kọmputa kan). Mo ni ọwọ meji (Cores). Awọn ẹrọ pupọ wa ninu ibi idana ounjẹ (IO): adiro, Kettle, toaster, firiji. Mo tan gaasi, fi pan didin kan sori rẹ ki o si da epo sinu rẹ laisi duro fun ki o gbona (asynchronously, Non-Ìdènà-IO-Duro), Mo mu awọn ẹyin naa kuro ninu firiji ki o si fọ wọn sinu awo kan, lẹhinna lu wọn pẹlu ọwọ kan (Oro #1), ati keji (Oro #2) dani awo (Pin Resource). Ni bayi Emi yoo fẹ lati tan ina, ṣugbọn emi ko ni ọwọ to (Ebi ebi) Ni akoko yii, pan-frying ngbona (Ṣiṣe abajade) sinu eyiti mo tú ohun ti mo ti nà. Mo de ikoko naa mo si tan-an mo si wo aimọgbọnwa omi ti n hó ninu rẹ (Ìdènà-IO-Duro), botilẹjẹpe ni akoko yii o le fọ awo naa nibiti o ti na omelet naa.

Mo ṣe omelet kan ni lilo awọn ọwọ meji nikan, ati pe Emi ko ni diẹ sii, ṣugbọn ni akoko kanna, ni akoko ti o pa omelette naa, awọn iṣẹ 2 waye ni ẹẹkan: lilu omelette, dani awo, gbigbona pan frying. Sipiyu jẹ apakan ti o yara julọ ti kọnputa, IO jẹ eyiti o jẹ igbagbogbo ohun gbogbo fa fifalẹ, nitorinaa nigbagbogbo ojutu ti o munadoko ni lati gba Sipiyu pẹlu nkan lakoko gbigba data lati IO.

Tẹsiwaju ni apejuwe:

  • Ti o ba wa ninu ilana ti ngbaradi omelet, Emi yoo tun gbiyanju lati yi aṣọ pada, eyi yoo jẹ apẹẹrẹ ti multitasking. Nuance pataki kan: awọn kọnputa dara julọ ni eyi ju eniyan lọ.
  • Ibi idana ounjẹ pẹlu ọpọlọpọ awọn olounjẹ, fun apẹẹrẹ ni ile ounjẹ kan - kọnputa pupọ-mojuto.
  • Ọpọlọpọ awọn ile ounjẹ ni agbala ounjẹ ni ile-iṣẹ rira kan - ile-iṣẹ data

Awọn irinṣẹ NET

NET dara ni ṣiṣẹ pẹlu awọn okun, bi pẹlu ọpọlọpọ awọn ohun miiran. Pẹlu ẹya tuntun kọọkan, o ṣafihan siwaju ati siwaju sii awọn irinṣẹ tuntun fun ṣiṣẹ pẹlu wọn, awọn fẹlẹfẹlẹ tuntun ti abstraction lori awọn okun OS. Nigbati o ba n ṣiṣẹ pẹlu ikole ti awọn abstractions, awọn olupilẹṣẹ ilana lo ọna ti o fi aye silẹ, nigba lilo abstraction ipele giga, lati lọ si isalẹ ọkan tabi diẹ sii awọn ipele ni isalẹ. Ni ọpọlọpọ igba eyi kii ṣe pataki, ni otitọ o ṣii ilẹkun si titu ararẹ ni ẹsẹ pẹlu ibọn kekere kan, ṣugbọn nigbamiran, ni awọn iṣẹlẹ to ṣe pataki, o le jẹ ọna kan nikan lati yanju iṣoro kan ti a ko yanju ni ipele ti abstraction lọwọlọwọ. .

Nipa awọn irinṣẹ, Mo tumọ si awọn atọkun siseto ohun elo mejeeji (APIs) ti a pese nipasẹ ilana ati awọn idii ẹnikẹta, bakanna bi gbogbo awọn solusan sọfitiwia ti o rọrun wiwa fun eyikeyi awọn iṣoro ti o ni ibatan si koodu asopo-pupọ.

Bibẹrẹ okun

Kilasi O tẹle jẹ kilasi ipilẹ julọ ni NET fun ṣiṣẹ pẹlu awọn okun. Olupilẹṣẹ gba ọkan ninu awọn aṣoju meji:

  • ThreadStart - Ko si awọn paramita
  • ParametrizedThreadStart - pẹlu paramita kan ti iru nkan.

Aṣoju naa yoo ṣiṣẹ ni okun tuntun ti o ṣẹda lẹhin pipe ọna Ibẹrẹ Ti o ba jẹ aṣoju iru ParametrizedThreadStart si oluṣeto, lẹhinna ohun kan gbọdọ kọja si ọna Ibẹrẹ. Ilana yii nilo lati gbe eyikeyi alaye agbegbe si ṣiṣan naa. O tọ lati ṣe akiyesi pe ṣiṣẹda okun jẹ iṣẹ ṣiṣe gbowolori, ati okun funrararẹ jẹ ohun ti o wuwo, o kere ju nitori pe o pin 1MB ti iranti lori akopọ ati nilo ibaraenisepo pẹlu OS API.

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

Kilasi ThreadPool duro fun imọran ti adagun-odo kan. Ni NET, adagun okun okun jẹ nkan ti imọ-ẹrọ, ati awọn ti o dagbasoke ni Microsoft ti fi ipa pupọ lati rii daju pe o ṣiṣẹ ni aipe ni ọpọlọpọ awọn oju iṣẹlẹ.

Erongba gbogbogbo:

Lati akoko ti ohun elo naa bẹrẹ, o ṣẹda ọpọlọpọ awọn okun ni ipamọ ni abẹlẹ ati pese agbara lati mu wọn fun lilo. Ti a ba lo awọn okun nigbagbogbo ati ni awọn nọmba nla, adagun-odo naa gbooro lati pade awọn iwulo olupe naa. Nigbati ko ba si awọn okun ọfẹ ninu adagun ni akoko ti o tọ, yoo duro fun ọkan ninu awọn okun lati pada, tabi ṣẹda tuntun kan. O tẹle pe adagun okun okun jẹ nla fun diẹ ninu awọn iṣe igba kukuru ati ko dara fun awọn iṣẹ ṣiṣe ti o ṣiṣẹ bi awọn iṣẹ jakejado gbogbo iṣẹ ohun elo naa.

Lati lo okun kan lati inu adagun-odo, ọna QueueUserWorkItem kan wa ti o gba aṣoju iru WaitCallback, eyiti o ni ibuwọlu kanna bi ParametrizedThreadStart, ati paramita ti o kọja si o ṣe iṣẹ kanna.

ThreadPool.QueueUserWorkItem(...);

Ọna adagun okun okun ti a ko mọ diẹ ti RegisterWaitForSingleObject ni a lo lati ṣeto awọn iṣẹ IO ti kii ṣe idinamọ. Aṣoju ti o kọja si ọna yii yoo pe nigbati WaitHandle ti kọja si ọna naa jẹ “Tusilẹ”.

ThreadPool.RegisterWaitForSingleObject(...)

NET ni aago okun ati pe o yatọ si awọn aago WinForms/WPF ni pe oluṣakoso rẹ yoo pe lori okun ti o ya lati inu adagun omi.

System.Threading.Timer

Ọna nla tun wa lati fi aṣoju ranṣẹ fun ipaniyan si okun kan lati inu adagun-odo - ọna BeginInvoke.

DelegateInstance.BeginInvoke

Emi yoo fẹ lati gbe ni ṣoki lori iṣẹ ti ọpọlọpọ awọn ọna ti o wa loke le ṣe pe - CreateThread lati Kernel32.dll Win32 API. Ọna kan wa, o ṣeun si ẹrọ ti awọn ọna ita, lati pe iṣẹ yii. Mo ti rii iru ipe kan ni ẹẹkan ni apẹẹrẹ ẹru ti koodu ohun-ini, ati iwuri ti onkọwe ti o ṣe deede eyi tun jẹ ohun ijinlẹ si mi.

Kernel32.dll CreateThread

Wiwo ati N ṣatunṣe aṣiṣe

Awọn okun ti o ṣẹda nipasẹ rẹ, gbogbo awọn paati ẹnikẹta, ati adagun NET ni a le wo ni window Awọn ọna ti Studio Visual. Ferese yii yoo ṣafihan alaye okun nikan nigbati ohun elo wa labẹ yokokoro ati ni ipo fifọ. Nibi o le ni irọrun wo awọn orukọ akopọ ati awọn pataki ti o tẹle ara kọọkan, ki o yipada n ṣatunṣe aṣiṣe si okun kan pato. Lilo ohun-ini pataki ti kilasi Okun, o le ṣeto pataki ti okun kan, eyiti OC ati CLR yoo rii bi iṣeduro nigbati o ba pin akoko ero isise laarin awọn okun.

NET: Awọn irinṣẹ fun ṣiṣẹ pẹlu multithreading ati asynchrony. Apa 1

Ibi ikawe Ti o jọra Iṣẹ

Ile-ikawe Parallel Task (TPL) ni a ṣe ni .NET 4.0. Bayi o jẹ boṣewa ati ọpa akọkọ fun ṣiṣẹ pẹlu asynchrony. Eyikeyi koodu ti o nlo ọna ti o ti dagba ni a gba pe ogún. Ẹka ipilẹ ti TPL jẹ iṣẹ-ṣiṣe kilasi lati System.Threading.Tasks namespace. Iṣẹ-ṣiṣe jẹ abstraction lori okun. Pẹlu ẹya tuntun ti ede C #, a ni ọna didara lati ṣiṣẹ pẹlu Awọn iṣẹ ṣiṣe - async/awọn oniṣẹ duro. Awọn imọran wọnyi jẹ ki o ṣee ṣe lati kọ koodu asynchronous bi ẹnipe o rọrun ati mimuuṣiṣẹpọ, eyi jẹ ki o ṣee ṣe paapaa fun awọn eniyan ti o ni oye kekere ti awọn iṣẹ inu ti awọn okun lati kọ awọn ohun elo ti o lo wọn, awọn ohun elo ti ko di didi nigbati o n ṣiṣẹ awọn iṣẹ pipẹ. Lilo async/duro jẹ koko-ọrọ fun ọkan tabi paapaa ọpọlọpọ awọn nkan, ṣugbọn Emi yoo gbiyanju lati gba alaye rẹ ni awọn gbolohun ọrọ diẹ:

  • async jẹ iyipada ti ọna ti o pada Iṣẹ-ṣiṣe tabi ofo
  • ati await jẹ oniṣẹ nduro Iṣẹ-ṣiṣe ti kii ṣe idinamọ.

Lẹẹkansi: oniṣẹ await, ni ọran gbogbogbo (awọn imukuro wa), yoo tu o tẹle ipaniyan lọwọlọwọ siwaju, ati nigbati Iṣẹ-ṣiṣe ba pari ipaniyan rẹ, ati okun (ni otitọ, yoo jẹ deede diẹ sii lati sọ ọrọ-ọrọ naa , ṣugbọn diẹ sii lori iyẹn nigbamii) yoo tẹsiwaju ṣiṣe ọna naa siwaju. Ninu NET, ilana yii jẹ imuse ni ọna kanna bi ipadabọ ikore, nigbati ọna kikọ ba yipada si gbogbo kilasi, eyiti o jẹ ẹrọ ipinlẹ ati pe o le ṣe ni awọn ege lọtọ ti o da lori awọn ipinlẹ wọnyi. Ẹnikẹni ti o nifẹ si le kọ koodu ti o rọrun eyikeyi nipa lilo asynс/duro, ṣajọ ati wo apejọ naa nipa lilo JetBrains dotPeek pẹlu Koodu Ti ipilẹṣẹ Compiler ṣiṣẹ.

Jẹ ki a wo awọn aṣayan fun ifilọlẹ ati lilo Iṣẹ-ṣiṣe. Ninu apẹẹrẹ koodu ni isalẹ, a ṣẹda iṣẹ-ṣiṣe tuntun ti ko ṣe nkan ti o wulo (Orun.Orun(10000)), ṣugbọn ni igbesi aye gidi eyi yẹ ki o jẹ diẹ ninu iṣẹ aladanla Sipiyu.

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
}

Iṣẹ-ṣiṣe kan ti ṣẹda pẹlu nọmba awọn aṣayan:

  • LongRunning jẹ itọka pe iṣẹ naa kii yoo pari ni iyara, eyiti o tumọ si pe o le tọ lati gbero lati ma mu o tẹle ara lati inu adagun-odo, ṣugbọn ṣiṣẹda lọtọ fun Iṣẹ-ṣiṣe yii ki o má ba ṣe ipalara fun awọn miiran.
  • AttachedToParent - Awọn iṣẹ-ṣiṣe le ṣee ṣeto ni ipo-iṣẹ. Ti a ba lo aṣayan yii, lẹhinna Iṣẹ-ṣiṣe le wa ni ipo nibiti o ti pari funrararẹ ati pe o nduro fun ipaniyan awọn ọmọ rẹ.
  • PreferFairness - tumọ si pe yoo dara lati ṣiṣẹ Awọn iṣẹ-ṣiṣe ti a firanṣẹ fun ipaniyan tẹlẹ ṣaaju awọn ti o firanṣẹ nigbamii. Ṣugbọn eyi jẹ iṣeduro nikan ati awọn abajade ko ni iṣeduro.

Paramita keji ti o kọja si ọna naa jẹ CancellationToken. Lati mu ifagile iṣẹ ṣiṣe ni deede lẹhin ti o ti bẹrẹ, koodu ti n ṣiṣẹ gbọdọ kun fun awọn sọwedowo fun ipinlẹ CancellationToken. Ti ko ba si awọn sọwedowo, lẹhinna ọna Fagilee ti a pe lori CancellationTokenSource ohun yoo ni anfani lati da ipaniyan ti Iṣẹ naa duro ṣaaju ki o to bẹrẹ.

Paramita ti o kẹhin jẹ ohun elo oluṣeto iru TaskScheduler. Kilasi yii ati awọn arọmọdọmọ rẹ jẹ apẹrẹ lati ṣakoso awọn ilana fun pinpin Awọn iṣẹ-ṣiṣe kọja awọn okun;

Oṣiṣẹ await ti lo si Iṣẹ-ṣiṣe ti o ṣẹda, eyiti o tumọ si koodu ti a kọ lẹhin rẹ, ti ọkan ba wa, yoo ṣiṣẹ ni ipo kanna (nigbagbogbo eyi tumọ si lori okun kanna) bi koodu ṣaaju duro.

Ọna naa ti samisi bi ofo async, eyiti o tumọ si pe o le lo oniṣẹ await, ṣugbọn koodu ipe kii yoo ni anfani lati duro fun ipaniyan. Ti iru ẹya bẹẹ ba jẹ dandan, lẹhinna ọna naa gbọdọ da Iṣẹ-ṣiṣe pada. Awọn ọna ti a samisi async ofo jẹ ohun ti o wọpọ: gẹgẹbi ofin, iwọnyi jẹ awọn olutọju iṣẹlẹ tabi awọn ọna miiran ti o ṣiṣẹ lori ina ati ilana gbagbe. Ti o ko ba nilo lati fun nikan ni anfani lati duro titi ti opin ipaniyan, ṣugbọn tun pada abajade, lẹhinna o nilo lati lo Iṣẹ-ṣiṣe.

Lori Iṣẹ-ṣiṣe ti ọna StartNew pada, ati lori eyikeyi miiran, o le pe ọna ConfigureAwait pẹlu paramita eke, lẹhinna ipaniyan lẹhin idaduro yoo tẹsiwaju kii ṣe lori ipo ti o gba, ṣugbọn lori lainidii. Eyi yẹ ki o ṣee nigbagbogbo nigbati ipo ipaniyan ko ṣe pataki fun koodu lẹhin idaduro. Eyi tun jẹ iṣeduro lati ọdọ MS nigba kikọ koodu ti yoo jẹ jiṣẹ ni akopọ ni ile-ikawe kan.

Jẹ ki a gbe diẹ diẹ sii lori bii o ṣe le duro de ipari Iṣẹ-ṣiṣe kan. Ni isalẹ jẹ apẹẹrẹ ti koodu, pẹlu awọn asọye lori nigba ti ireti ti ṣe ni ipo daradara ati nigbati o ba ṣe ni aiṣamuyẹ.

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
}

Ni apẹẹrẹ akọkọ, a duro fun Iṣẹ-ṣiṣe lati pari laisi idinamọ okun ipe;

Ni aṣayan keji, a ṣe idiwọ okun ipe titi ti abajade ọna naa yoo fi ṣe iṣiro. Eyi jẹ buburu kii ṣe nitori pe a ti gba okun kan, iru orisun ti o niyelori ti eto naa, pẹlu aisimi ti o rọrun, ṣugbọn tun nitori pe koodu ti ọna ti a pe ni o duro de, ati pe ipo imuṣiṣẹpọ nilo ipadabọ si okun ipe lẹhin. duro, lẹhinna a yoo gba titiipa kan: Okun pipe n duro lakoko ti abajade ti ọna asynchronous ti ṣe iṣiro, ọna asynchronous gbiyanju lasan lati tẹsiwaju ipaniyan rẹ ni okun ipe.

Alailanfani miiran ti ọna yii jẹ mimu aṣiṣe idiju. Otitọ ni pe awọn aṣiṣe ni koodu asynchronous nigba lilo async/duro jẹ rọrun pupọ lati mu - wọn huwa kanna bi pe koodu naa jẹ amuṣiṣẹpọ. Lakoko ti a ba lo exorcism idaduro amuṣiṣẹpọ si Iṣẹ-ṣiṣe kan, imukuro atilẹba yipada si AggregateException, i.e. Lati mu imukuro naa, iwọ yoo ni lati ṣayẹwo iru InnerException ki o kọ ohun ti o ba jẹ ẹwọn funrararẹ ninu bulọọki apeja kan tabi lo apeja nigbati o ba kọ, dipo pq awọn bulọọki apeja ti o faramọ ni agbaye C #.

Awọn apẹẹrẹ kẹta ati ikẹhin tun jẹ aami buburu fun idi kanna ati pe o ni gbogbo awọn iṣoro kanna.

NigbatiAny ati Nigbati Gbogbo awọn ọna jẹ irọrun pupọ fun iduro fun ẹgbẹ kan ti Awọn iṣẹ-ṣiṣe;

Awọn okun idaduro

Fun orisirisi idi, o le jẹ pataki lati da awọn sisan lẹhin ti o ti bere. Awọn ọna pupọ lo wa lati ṣe eyi. Kilasi Thread ni awọn ọna ti a darukọ meji ti o yẹ: Kọ silẹ и Idilọwọ. Ni igba akọkọ ti ọkan ti wa ni gíga ko niyanju fun lilo, nitori lẹhin pipe ni eyikeyi akoko laileto, lakoko sisẹ eyikeyi itọnisọna, imukuro yoo da silẹ ThreadAbortedException. O ko nireti iru imukuro bẹ lati jabọ nigbati o ba n pọ si eyikeyi oniyipada odidi, otun? Ati nigba lilo ọna yii, eyi jẹ ipo gidi kan. Ti o ba nilo lati ṣe idiwọ CLR lati ṣe ipilẹṣẹ iru iyasọtọ ni apakan kan ti koodu, o le fi ipari si ni awọn ipe Thread.BeginCriticalRegion, Thread.EndCriticalRegion. Eyikeyi koodu ti a kọ sinu bulọki nipari ni a we sinu iru awọn ipe. Fun idi eyi, ninu awọn ijinle koodu ilana o le wa awọn bulọọki pẹlu igbiyanju ofo, ṣugbọn kii ṣe ofo nikẹhin. Microsoft ṣe irẹwẹsi ọna yii pupọ ti wọn ko fi sii ninu .net mojuto.

Ọna Idilọwọ n ṣiṣẹ ni asọtẹlẹ diẹ sii. O le da o tẹle ara pẹlu ohun sile ThreadInterruptedException nikan ni awọn akoko wọnyẹn nigbati o tẹle ara wa ni ipo idaduro. O wọ inu ipo yii lakoko ti o nduro lakoko ti o nduro fun WaitHandle, titiipa, tabi lẹhin pipe Thread.Sleep.

Awọn aṣayan mejeeji ti a ṣalaye loke jẹ buburu nitori airotẹlẹ wọn. Ojutu ni lati lo eto kan CancellationToken ati kilasi CancellationTokenOrisun. Koko naa ni eyi: apẹẹrẹ ti kilasi CancellationTokenSource ti ṣẹda ati pe ẹni ti o ni nikan le da iṣẹ naa duro nipa pipe ọna naa. fagilee. CancellationToken nikan ni o kọja si iṣẹ naa funrararẹ. Awọn oniwun CancellationToken ko le fagile iṣẹ naa funrararẹ, ṣugbọn o le ṣayẹwo boya a ti fagile iṣẹ naa. Ohun-ini Boolean wa fun eyi Ti beere fun Ifagile ati ọna JuIfFagilee Beere. Awọn igbehin yoo jabọ ohun sile TaskCancelledException ti o ba ti Fagilee ọna ti a npe ni lori awọn CancellationToken apẹẹrẹ ni parroted. Ati pe eyi ni ọna ti Mo ṣeduro lilo. Eyi jẹ ilọsiwaju lori awọn aṣayan iṣaaju nipa gbigba iṣakoso ni kikun ni aaye wo ni iṣẹ iyasọtọ le ṣe parẹ.

Aṣayan buruju julọ fun didaduro okun ni lati pe iṣẹ Win32 API TerminateThread. Iwa ti CLR lẹhin pipe iṣẹ yii le jẹ airotẹlẹ. Lori MSDN awọn atẹle ni a kọ nipa iṣẹ yii: “TerminateThread jẹ iṣẹ ti o lewu ti o yẹ ki o lo nikan ni awọn ọran ti o buruju julọ. "

Iyipada API ti ogún si Iṣẹ-ṣiṣe ti o da ni lilo ọna FromAsync

Ti o ba ni orire to lati ṣiṣẹ lori iṣẹ akanṣe kan ti o bẹrẹ lẹhin ti awọn iṣẹ-ṣiṣe ti ṣe ifilọlẹ ati dawọ lati fa ẹru idakẹjẹ fun ọpọlọpọ awọn olupilẹṣẹ, lẹhinna iwọ kii yoo ni lati koju ọpọlọpọ awọn API atijọ, awọn ẹni-kẹta ati awọn ẹgbẹ rẹ ti jiya ni igba atijọ. Ni Oriire, ẹgbẹ .NET Framework ṣe abojuto wa, botilẹjẹpe boya ibi-afẹde ni lati tọju ara wa. Bi o ṣe le jẹ, NET ni awọn irinṣẹ pupọ fun iyipada koodu ti ko ni irora ti a kọ sinu awọn isunmọ siseto asynchronous atijọ si tuntun. Ọkan ninu wọn ni ọna FromAsync ti TaskFactory. Ni apẹẹrẹ koodu ti o wa ni isalẹ, Mo fi ipari si awọn ọna async atijọ ti WebRequest kilasi ni Iṣẹ-ṣiṣe nipa lilo ọna yii.

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

Eyi jẹ apẹẹrẹ nikan ati pe o ko ṣeeṣe lati ni lati ṣe eyi pẹlu awọn iru ti a ṣe sinu, ṣugbọn eyikeyi iṣẹ akanṣe atijọ n kan ni irọrun pẹlu awọn ọna BeginDoSomething ti o pada IAsyncResult ati awọn ọna EndDoSomething ti o gba.

Ṣe iyipada API si Ipilẹ Iṣẹ-ṣiṣe ni lilo kilasi TaskCompletionSource

Ọpa pataki miiran lati ronu ni kilasi naa TaskCompletionOrisun. Ni awọn ofin ti awọn iṣẹ, idi ati ilana iṣiṣẹ, o le jẹ iranti diẹ ti ọna RegisterWaitForSingleObject ti kilasi ThreadPool, eyiti Mo kowe nipa loke. Lilo kilasi yii, o le ni irọrun ati irọrun fi ipari si awọn API asynchronous atijọ ni Awọn iṣẹ ṣiṣe.

Iwọ yoo sọ pe Mo ti sọrọ tẹlẹ nipa ọna FromAsync ti kilasi TaskFactory ti a pinnu fun awọn idi wọnyi. Nibi a yoo ni lati ranti gbogbo itan-akọọlẹ ti idagbasoke ti awọn awoṣe asynchronous ni .net ti Microsoft ti funni ni awọn ọdun 15 sẹhin: ṣaaju Ilana Asynchronous Based (TAP), Asynchronous Programming Pattern (APP), eyiti o wa. wà nipa awọn ọna BẹrẹDoSnkan ti n pada Esi IAsync ati awọn ọna opinDoSomenkan ti o gba ati fun ohun-ini ti awọn ọdun wọnyi ọna FromAsync jẹ pipe, ṣugbọn ni akoko pupọ, o rọpo nipasẹ Ilana Asynchronous Based Event (ATI AP), eyiti o ro pe iṣẹlẹ kan yoo dide nigbati iṣẹ asynchronous ba pari.

TaskCompletionSource jẹ pipe fun sisọ Awọn iṣẹ ṣiṣe ati awọn API ti o jẹ ti ara ti a ṣe ni ayika awoṣe iṣẹlẹ. Koko-ọrọ ti iṣẹ rẹ jẹ bi atẹle: ohun kan ti kilasi yii ni ohun-ini gbogbogbo ti Iru Iṣẹ-ṣiṣe, ipo eyiti o le ṣakoso nipasẹ SetResult, SetException, ati bẹbẹ lọ awọn ọna ti kilasi TaskCompletionSource. Ni awọn aaye nibiti a ti lo oniṣẹ await si Iṣẹ-ṣiṣe yii, yoo ṣee ṣe tabi kuna pẹlu iyasọtọ ti o da lori ọna ti a lo si TaskCompletionSource. Ti ko ba ṣiyemeji, jẹ ki a wo apẹẹrẹ koodu yii, nibiti diẹ ninu EAP API atijọ ti wa ni ipari si Iṣẹ-ṣiṣe kan nipa lilo TaskCompletionSource: nigbati iṣẹlẹ naa ba tan, iṣẹ naa yoo gbe si ipo Ipari, ati ọna ti o lo oniṣẹ ti nduro. si Iṣẹ-ṣiṣe yii yoo tun bẹrẹ ipaniyan rẹ lẹhin ti o ti gba nkan naa esi.

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 Italolobo & Ẹtan

Wiwa awọn API atijọ kii ṣe gbogbo ohun ti o le ṣee ṣe ni lilo TaskCompletionSource. Lilo kilasi yii ṣii aye ti o nifẹ lati ṣe apẹrẹ ọpọlọpọ awọn API lori Awọn iṣẹ ṣiṣe ti ko gba awọn okun. Ati ṣiṣan naa, bi a ṣe ranti, jẹ orisun ti o gbowolori ati pe nọmba wọn ni opin (nipataki nipasẹ iye Ramu). Idiwọn yii le ni irọrun ni irọrun nipasẹ idagbasoke, fun apẹẹrẹ, ohun elo wẹẹbu ti kojọpọ pẹlu ọgbọn iṣowo ti o nipọn. Jẹ ki a ro awọn iṣeeṣe ti Mo n sọrọ nipa nigba imuse iru ẹtan bi Long-Polling.

Ni kukuru, pataki ti ẹtan ni eyi: o nilo lati gba alaye lati API nipa diẹ ninu awọn iṣẹlẹ ti o waye ni ẹgbẹ rẹ, nigba ti API, fun idi kan, ko le ṣe iroyin iṣẹlẹ naa, ṣugbọn o le pada ipinle nikan. Apeere ti iwọnyi jẹ gbogbo awọn API ti a ṣe si oke HTTP ṣaaju awọn akoko WebSocket tabi nigbati ko ṣee ṣe fun idi kan lati lo imọ-ẹrọ yii. Onibara le beere lọwọ olupin HTTP. Olupin HTTP ko le funrararẹ bẹrẹ ibaraẹnisọrọ pẹlu alabara. Ojutu ti o rọrun ni lati didi olupin naa nipa lilo aago kan, ṣugbọn eyi ṣẹda fifuye afikun lori olupin naa ati idaduro afikun ni apapọ TimerInterval / 2. Lati wa ni ayika eyi, ẹtan kan ti a pe ni Idibo Gigun ni a ṣẹda, eyiti o pẹlu idaduro idahun lati ọdọ. olupin naa titi ti Aago yoo fi pari tabi iṣẹlẹ yoo waye. Ti iṣẹlẹ naa ba ti waye, lẹhinna o ti ni ilọsiwaju, ti kii ba ṣe bẹ, lẹhinna ibeere naa ni a firanṣẹ lẹẹkansi.

while(!eventOccures && !timeoutExceeded)  {

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

Ṣugbọn iru ojutu kan yoo jẹri lati jẹ ẹru ni kete ti nọmba awọn alabara ti nduro fun iṣẹlẹ naa pọ si, nitori… Olukuluku iru alabara wa ni gbogbo okun ti nduro fun iṣẹlẹ kan. Bẹẹni, ati pe a gba idaduro 1ms afikun nigbati iṣẹlẹ naa ba fa, ni igbagbogbo eyi kii ṣe pataki, ṣugbọn kilode ti o jẹ ki sọfitiwia buru ju bi o ti le jẹ? Ti a ba yọ Thread.Sleep (1), lẹhinna ni asan a yoo gbe ero isise kan mojuto 100% laišišẹ, yiyi ni iyipo ti ko wulo. Lilo TaskCompletionSource o le ni rọọrun ṣe koodu yii ki o yanju gbogbo awọn iṣoro ti a damọ loke:

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

Yi koodu ni ko gbóògì-setan, sugbon o kan demo. Lati lo ni awọn ọran gidi, o tun nilo, ni o kere ju, lati mu ipo naa ṣiṣẹ nigbati ifiranṣẹ ba de ni akoko ti ko si ẹnikan ti o nireti: ninu ọran yii, ọna AsseptMessageAsync yẹ ki o pada Iṣẹ-ṣiṣe ti o ti pari tẹlẹ. Ti eyi ba jẹ ọran ti o wọpọ julọ, lẹhinna o le ronu nipa lilo ValueTask.

Nigba ti a ba gba ibeere kan fun ifiranṣẹ, a ṣẹda ati gbe TaskCompletionSource sinu iwe-itumọ, ati lẹhinna duro fun ohun ti o ṣẹlẹ ni akọkọ: aarin akoko pàtó kan dopin tabi ifiranṣẹ kan ti gba.

ValueTask: idi ati bi

Awọn oniṣẹ async / nduro, bii oniṣẹ ipadabọ ikore, ṣe ipilẹṣẹ ẹrọ ipinlẹ kan lati ọna naa, ati pe eyi ni ṣiṣẹda ohun tuntun kan, eyiti o fẹrẹ jẹ nigbagbogbo kii ṣe pataki, ṣugbọn ni awọn ọran toje o le ṣẹda iṣoro kan. Ọran yii le jẹ ọna ti a pe ni igbagbogbo, a n sọrọ nipa awọn mewa ati awọn ọgọọgọrun awọn ipe fun iṣẹju keji. Ti iru ọna bẹẹ ba ti kọ ni ọna ti o jẹ pe ni ọpọlọpọ awọn ọran o pada abajade ti o kọja gbogbo awọn ọna ti nduro, lẹhinna NET pese ohun elo kan lati mu eyi dara si - eto ValueTask. Lati jẹ ki o ye wa, jẹ ki a wo apẹẹrẹ ti lilo rẹ: kaṣe kan wa ti a lọ si nigbagbogbo. Awọn iye diẹ wa ninu rẹ lẹhinna a da wọn pada ti ko ba ṣe bẹ, lẹhinna a lọ si diẹ ninu IO o lọra lati gba wọn. Mo fẹ lati ṣe igbehin asynchronously, eyi ti o tumo si gbogbo ọna wa ni jade lati wa ni asynchronous. Nitorinaa, ọna ti o han gbangba lati kọ ọna jẹ bi atẹle:

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

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

Nitori ifẹ lati mu diẹ sii, ati iberu diẹ ti ohun ti Roslyn yoo ṣe nigbati o ba n ṣajọ koodu yii, o le tun apẹẹrẹ yii kọ bi atẹle:

public Task<string> GetById(int id) {

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

Lootọ, ojutu ti o dara julọ ninu ọran yii yoo jẹ lati mu ọna ti o gbona pọ si, eyun, gbigba iye kan lati inu iwe-itumọ laisi eyikeyi awọn ipin ti ko wulo ati fifuye lori GC, lakoko ti awọn ọran toje wọnyẹn nigba ti a tun nilo lati lọ si IO fun data. , ohun gbogbo yoo wa ni afikun / iyokuro ọna atijọ:

public ValueTask<string> GetById(int id) {

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

Jẹ ki a ṣe akiyesi nkan ti koodu yii: ti iye kan ba wa ninu kaṣe, a ṣẹda eto kan, bibẹẹkọ iṣẹ-ṣiṣe gidi yoo wa ni itumọ kan. Koodu ipe naa ko bikita ọna wo ni koodu yii ti ṣiṣẹ ni: ValueTask, lati oju wiwo sintasi C # kan, yoo huwa kanna gẹgẹbi Iṣẹ-ṣiṣe deede ninu ọran yii.

TaskSchedulers: Ṣiṣakoṣo awọn ilana ifilọlẹ iṣẹ-ṣiṣe

API atẹle ti Emi yoo fẹ lati gbero ni kilasi naa Iṣeto iṣẹ-ṣiṣe ati awọn itọsẹ rẹ. Mo ti sọ tẹlẹ loke pe TPL ni agbara lati ṣakoso awọn ilana fun pinpin Awọn iṣẹ-ṣiṣe kọja awọn okun. Iru awọn ilana bẹẹ jẹ asọye ninu awọn ọmọ ẹgbẹ ti TaskScheduler. Fere eyikeyi ilana ti o le nilo ni a le rii ni ile-ikawe. ParallelExtensionsExtras, ni idagbasoke nipasẹ Microsoft, sugbon ko ara ti .NET, ṣugbọn pese bi a Nuget package. Jẹ ki a wo diẹ ninu wọn ni ṣoki:

  • CurrentThreadTaskScheduler - ṣiṣẹ Awọn iṣẹ-ṣiṣe lori okun lọwọlọwọ
  • LimitedConcurrencyLevelTaskScheduler - ṣe opin nọmba awọn iṣẹ-ṣiṣe ti a ṣe nigbakanna nipasẹ paramita N, eyiti o gba ninu olupilẹṣẹ
  • Ti paṣẹTaskScheduler - ti wa ni asọye bi LimitedConcurrencyLevelTaskScheduler(1), nitorinaa awọn iṣẹ ṣiṣe yoo ṣee ṣe ni lẹsẹsẹ.
  • WorkStealingTaskScheduler - awọn ohun elo jija iṣẹ ona si pinpin iṣẹ-ṣiṣe. Ni pataki o jẹ ThreadPool lọtọ. Yanju iṣoro naa pe ni NET ThreadPool jẹ kilasi aimi, ọkan fun gbogbo awọn ohun elo, eyiti o tumọ si pe ikojọpọ rẹ tabi lilo ti ko tọ ni apakan kan ti eto naa le ja si awọn ipa ẹgbẹ ni omiiran. Pẹlupẹlu, o jẹ gidigidi soro lati ni oye idi ti iru awọn abawọn. Iyẹn. O le nilo lati lo WorkStealingTaskSchedulers lọtọ ni awọn apakan ti eto nibiti lilo ThreadPool le jẹ ibinu ati airotẹlẹ.
  • QueuedTaskScheduler - faye gba o lati ṣe awọn iṣẹ-ṣiṣe ni ibamu si awọn ofin isinyi ayo
  • ThreadPerTaskScheduler - ṣẹda okun lọtọ fun Iṣẹ-ṣiṣe kọọkan ti a ṣe lori rẹ. Le jẹ iwulo fun awọn iṣẹ ṣiṣe ti o gba akoko pipẹ airotẹlẹ lati pari.

Alaye to dara wa nkan nipa TaskSchedulers lori bulọọgi microsoft.

Fun irọrun ti n ṣatunṣe ohun gbogbo ti o ni ibatan si Awọn iṣẹ-ṣiṣe, Studio Visual ni window Awọn iṣẹ-ṣiṣe kan. Ni window yii o le rii ipo lọwọlọwọ ti iṣẹ-ṣiṣe ki o fo si laini koodu ti n ṣiṣẹ lọwọlọwọ.

NET: Awọn irinṣẹ fun ṣiṣẹ pẹlu multithreading ati asynchrony. Apa 1

PLinq ati awọn Parallel kilasi

Ni afikun si Awọn iṣẹ-ṣiṣe ati ohun gbogbo ti a sọ nipa wọn, awọn irinṣẹ meji ti o nifẹ si wa ni NET: PLinq (Linq2Parallel) ati kilasi Parallel. Ni igba akọkọ ti awọn ileri ipaniyan ni afiwe ti gbogbo awọn iṣẹ Linq lori ọpọlọpọ awọn okun. Nọmba awọn okun le jẹ tunto nipa lilo ọna itẹsiwaju WithDegreeOfParallelism. Laanu, nigbagbogbo PLinq ni ipo aiyipada rẹ ko ni alaye ti o to nipa awọn inu ti orisun data rẹ lati pese ere iyara pataki, ni apa keji, idiyele igbiyanju jẹ kekere: o kan nilo lati pe ọna AsParalle ṣaaju ki o to. pq ti awọn ọna Linq ati ṣiṣe awọn idanwo iṣẹ. Pẹlupẹlu, o ṣee ṣe lati ṣe alaye afikun si PLinq nipa iru orisun data rẹ nipa lilo ẹrọ Awọn ipin. O le ka diẹ ẹ sii nibi и nibi.

Kilasi aimi ti o jọra n pese awọn ọna fun aṣetunṣe nipasẹ ikojọpọ Foreach ni afiwe, ṣiṣe kan Fun lupu, ati ṣiṣe awọn aṣoju lọpọlọpọ ni Ipe ni afiwe. Iṣiṣẹ ti okun lọwọlọwọ yoo da duro titi awọn iṣiro yoo pari. Nọmba awọn okun le jẹ tunto nipasẹ gbigbe ParallelOptions bi ariyanjiyan to kẹhin. O tun le pato TaskScheduler ati CancellationToken nipa lilo awọn aṣayan.

awari

Nigbati mo bẹrẹ kikọ nkan yii da lori awọn ohun elo ti ijabọ mi ati alaye ti Mo gba lakoko iṣẹ mi lẹhin rẹ, Emi ko nireti pe yoo jẹ pupọ julọ. Ní báyìí, nígbà tí olùṣàtúnṣe ọ̀rọ̀ inú rẹ̀ tí mò ń tẹ̀wé àpilẹ̀kọ yìí bá sọ fún mi lọ́nà ẹ̀gàn pé ojú ìwé 15 ti lọ, màá ṣàkópọ̀ àwọn àbájáde ìgbà díẹ̀. Awọn ẹtan miiran, APIs, awọn irinṣẹ wiwo ati awọn ọfin ni yoo bo ni nkan ti nbọ.

Awọn ipinnu:

  • O nilo lati mọ awọn irinṣẹ fun ṣiṣẹ pẹlu awọn okun, asynchrony ati parallelism lati le lo awọn orisun ti awọn PC ode oni.
  • NET ni ọpọlọpọ awọn irinṣẹ oriṣiriṣi fun awọn idi wọnyi
  • Kii ṣe gbogbo wọn han ni ẹẹkan, nitorinaa o le rii awọn ohun-ini nigbagbogbo, sibẹsibẹ, awọn ọna wa lati ṣe iyipada awọn API atijọ laisi ipa pupọ.
  • Nṣiṣẹ pẹlu awọn okun ni NET jẹ aṣoju nipasẹ awọn kilasi Thread ati ThreadPool
  • Awọn ọna Thread.Abort, Thread.Interrupt, ati Win32 API TerminateThread jẹ ewu ati pe ko ṣe iṣeduro fun lilo. Dipo, o dara lati lo ẹrọ CancellationToken
  • Sisan jẹ orisun ti o niyelori ati ipese rẹ ni opin. Awọn ipo nibiti awọn okun n ṣiṣẹ nduro fun awọn iṣẹlẹ yẹ ki o yago fun. Fun eyi o rọrun lati lo kilasi TaskCompletionSource
  • Awọn irinṣẹ .NET ti o lagbara julọ ati ilọsiwaju fun ṣiṣẹ pẹlu parallelism ati asynchrony jẹ Awọn iṣẹ-ṣiṣe.
  • Awọn oniṣẹ c # async/duro n ṣe imuse erongba ti idaduro ti kii ṣe idinamọ
  • O le ṣakoso pinpin awọn iṣẹ-ṣiṣe kọja awọn okun ni lilo awọn kilasi ti a mu TaskScheduler
  • Ilana ValueTask le wulo ni jijẹ awọn ọna-gbigbona ati ijabọ-iranti
  • Awọn iṣẹ-ṣiṣe ti Studio Visual ati Awọn window window pese alaye pupọ ti o wulo fun ṣiṣatunṣe olona-asapo tabi koodu asynchronous
  • PLinq jẹ ohun elo ti o tutu, ṣugbọn o le ma ni alaye ti o to nipa orisun data rẹ, ṣugbọn eyi le ṣe atunṣe nipa lilo ẹrọ ipin.
  • A tun ma a se ni ojo iwaju…

orisun: www.habr.com

Fi ọrọìwòye kun