Programavimas

Kada .NET naudoti „Task.WaitAll“ ir „Task.WhenAll“

TPL („Task Parallel Library“) yra viena įdomiausių naujų funkcijų, įtrauktų į naujausias .NET Framework versijas. „Task.WaitAll“ ir „Task.WhenAll“ metodai yra du svarbūs ir dažnai naudojami TPL metodai.

„Task.WaitAll“ blokuoja dabartinę giją, kol visos kitos užduotys bus baigtos. Metodas „Task.WhenAll“ naudojamas sukurti užduotį, kuri bus įvykdyta tik tada, kai bus įvykdytos visos kitos užduotys.

Taigi, jei naudojate „Task.WhenAll“, gausite neužbaigtą užduoties objektą. Tačiau tai neužblokuos, bet leis vykdyti programą. Priešingai, „Task.WaitAll“ metodo iškvietimas iš tikrųjų blokuoja ir laukia, kol bus atliktos visos kitos užduotys.

Iš esmės „Task.WhenAll“ suteiks jums neužbaigtą užduotį, tačiau galite naudoti „ContinueWith“, kai tik nurodytos užduotys bus atliktos. Atkreipkite dėmesį, kad nei „Task.WhenAll“, nei „Task.WaitAll“ iš tikrųjų nevykdys užduočių; y., šiais metodais nėra pradedamos jokios užduotys. Štai kaip „ContinueWith“ naudojamas su „Task.WhenAll“:

Task.WhenAll (taskList) .ContinueWith (t => {

// čia parašyk savo kodą

});

Kaip teigiama „Microsoft“ dokumentuose, „Task.WhenAll“ „sukuria užduotį, kuri bus baigta, kai bus baigti visi užduoties objektai iš nesuskaičiuojamos kolekcijos“.

Task.WhenAll prieš Task.WaitAll

Leiskite man paaiškinti šių dviejų metodų skirtumą paprastu pavyzdžiu. Tarkime, kad turite užduotį, kuri atlieka tam tikrą veiklą su vartotojo sąsajos gija - tarkime, tam tikrą animaciją reikia parodyti vartotojo sąsajoje. Dabar, jei naudosite „Task.WaitAll“, vartotojo sąsaja bus užblokuota ir nebus atnaujinta, kol nebus atliktos visos susijusios užduotys ir blokas nebus atleistas. Tačiau, jei naudojate „Task.WhenAll“ toje pačioje programoje, vartotojo sąsajos gija nebus užblokuota ir bus atnaujinta kaip įprasta.

Taigi kurį iš šių metodų turėtumėte naudoti kada? Na, galite naudoti „WaitAll“, kai ketinimas sinchroniškai blokuoja, kad gautumėte rezultatus. Bet kai norėtumėte panaudoti asinchroniją, norėtumėte naudoti „WhenAll“ variantą. Galite laukti „Task.WhenAll“ neužblokuodami dabartinės gijos. Taigi, galbūt norėsite naudoti laukti naudodami „Task.WhenAll“ asinchroninio metodo viduje.

Kol „Task.WaitAll“ blokuoja dabartinę giją, kol visos laukiančios užduotys bus baigtos, „Task.WhenAll“ grąžins užduoties objektą. „Task.WaitAll“ išmeta „AggregateException“, kai viena ar kelios užduotys išmeta išimtį. Kai viena ar kelios užduotys išmeta išimtį ir laukiate užduoties. Kai „All“ metodas, jis išvynioja „AggregateException“ ir pateikia tik pirmąją.

Venkite naudoti užduotį. Vykdykite ciklais

Užduotis galite naudoti, kai norite atlikti vienu metu vykdomą veiklą. Jei jums reikia didelio lygiagretumo, užduotys niekada nėra geras pasirinkimas. ASP.Net visada patartina vengti sriegio telkinio gijų. Taigi turėtumėte susilaikyti nuo „Task.Run“ arba „Task.factory.StartNew“ naudojimo ASP.Net.

„Task.Run“ visada turėtų būti naudojamas susiejant procesoriaus kodą. „Task.Run“ nėra tinkamas pasirinkimas ASP.Net programose arba programose, kurios naudoja ASP.Net vykdymo laiką, nes jis tiesiog perkelia darbą į „ThreadPool“ giją. Jei naudojate „ASP.Net Web API“, užklausoje jau naudojama „ThreadPool“ gija. Taigi, jei naudojate „Task.Run“ savo ASP.Net žiniatinklio API programoje, jūs tiesiog apribojate mastelio mastą perkeldami darbą į kitą darbuotojo giją be jokios priežasties.

Atminkite, kad naudojant „Task.Run“ yra trūkumas. Jei ciklo viduje naudojate metodą „Task.Run“, bus sukurtos kelios užduotys - po vieną kiekvienam darbo ar iteracijos vienetui. Tačiau jei naudojate „Parallel.ForEach“ vietoj to, kad naudosite „Task.Run“ cikle, skaidinys sukuriamas, kad būtų išvengta daugiau užduočių, kad būtų galima atlikti veiklą, nei reikia. Tai gali žymiai pagerinti našumą, nes galite išvengti per daug kontekstinių jungiklių ir vis tiek panaudoti kelis savo sistemos branduolius.

Reikėtų pažymėti, kad „Parallel.ForEach“ naudoja „Partitioner“ viduje, kad paskirstytų kolekciją į darbo elementus. Beje, šis paskirstymas įvyksta ne kiekvienai užduočių elementų sąraše, o kaip paketui. Tai sumažina pridėtines išlaidas ir taip pagerina našumą. Kitaip tariant, jei naudojate „Task.Run“ arba „Task.Factory.StartNew“ ciklo viduje, jie aiškiai sukurs naujas užduotis kiekvienai kilpos iteracijai. Parallel.ForEach yra daug efektyvesnis, nes jis optimizuos vykdymą paskirstydamas darbo krūvį keliems jūsų sistemos šerdims.