Ohjelmointi

Milloin Task.WaitAll vs. Task.WhenAll on .NET-verkossa

TPL (Task Parallel Library) on yksi mielenkiintoisimmista uusista ominaisuuksista, jotka on lisätty .NET-kehyksen uusimpiin versioihin. Task.WaitAll- ja Task.WhenAll-menetelmät ovat kaksi tärkeää ja usein käytettyä menetelmää TPL: ssä.

Task.WaitAll estää nykyisen ketjun, kunnes kaikki muut tehtävät on suoritettu loppuun. Task.WhenAll-menetelmää käytetään tehtävän luomiseen, joka suoritetaan vain silloin, kun kaikki muut tehtävät on suoritettu.

Joten jos käytät Task.WhenAll-toimintoa, saat tehtäväobjektin, joka ei ole täydellinen. Se ei kuitenkaan estä, vaan antaa ohjelman suorittaa. Päinvastoin, Task.WaitAll-menetelmäkutsu todella estää ja odottaa kaikkien muiden tehtävien suorittamista.

Pohjimmiltaan Task.WhenAll antaa sinulle tehtävän, joka ei ole valmis, mutta voit käyttää ContinueWith -ohjelmaa heti, kun määritetyt tehtävät ovat suorittaneet suorituksensa. Huomaa, että Task.WhenAll eikä Task.WaitAll eivät tosiasiassa suorita tehtäviä; ts. tehtäviä ei aloiteta näillä menetelmillä. Näin ContinueWithia käytetään Task.WhenAll: n kanssa:

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

// kirjoita koodi tähän

});

Kuten Microsoftin dokumentaatiossa todetaan, Task.WhenAll "luo tehtävän, joka suoritetaan loppuun, kun kaikki lukemattoman kokoelman Task-objektit ovat valmiit".

Task.WhenAll vs. Task.WaitAll

Sallikaa minun selittää näiden kahden menetelmän ero yksinkertaisella esimerkillä. Oletetaan, että sinulla on tehtävä, joka suorittaa jonkin verran toimintaa käyttöliittymän ketjulla - sanotaan, että jotkut animaatiot on näytettävä käyttöliittymässä. Jos nyt käytät Task.WaitAll, käyttöliittymä estetään eikä sitä päivitetä ennen kuin kaikki siihen liittyvät tehtävät on suoritettu ja lohko vapautettu. Jos kuitenkin käytät Task.WhenAll-sovellusta samassa sovelluksessa, käyttöliittymäketjua ei estetä ja se päivitetään tavalliseen tapaan.

Joten mitä näistä menetelmistä sinun tulisi käyttää milloin? No, voit käyttää WaitAllia, kun tarkoitus estää synkronisesti tulosten saamiseksi. Mutta kun haluat hyödyntää asynkroniaa, haluat käyttää WhenAll-muunnosta. Voit odottaa Task.WhenAll ilman, että sinun on estettävä nykyistä ketjua. Siksi saatat haluta käyttää awaitia Task.WhenAll-asynkronimenetelmän sisällä.

Kun Task.WaitAll estää nykyisen ketjun, kunnes kaikki odottavat tehtävät on suoritettu, Task.WhenAll palauttaa tehtäväobjektin. Task.WaitAll heittää AggregateExceptionin, kun yksi tai useampi tehtävä heittää poikkeuksen. Kun yksi tai useampi tehtävä heittää poikkeuksen ja odotat Task.WhenAll-menetelmää, se purkaa AggregateExceptionin ja palauttaa vain ensimmäisen.

Vältä Task.Run -silmukoiden käyttöä

Voit käyttää tehtäviä, kun haluat suorittaa samanaikaisia ​​toimintoja. Jos tarvitset paljon rinnakkaisuutta, tehtävät eivät ole koskaan hyvä valinta. On aina suositeltavaa välttää langankierteen langan käyttöä ASP.Netissä. Siksi sinun on pidättäydyttävä käyttämästä Task.Run tai Task.factory.StartNew ASP.Netissä.

Task.Run-ohjelmaa tulisi käyttää aina prosessorin sidottuun koodiin. Task.Run ei ole hyvä valinta ASP.Net-sovelluksissa tai sovelluksissa, jotka hyödyntävät ASP.Net-ajonaikaa, koska se vain siirtää työn ThreadPool-säikeeksi. Jos käytät ASP.Net Web -sovellusliittymää, pyyntö käyttää jo ThreadPool-ketjua. Jos siis käytät Task.Run-ohjelmaa ASP.Net Web API -sovelluksessa, rajoitat vain skaalautuvuutta siirtämällä työn toiseen työntekijän säikeeseen ilman mitään syytä.

Huomaa, että Task.Run-toiminnossa on haitta. Jos käytät Task.Run-menetelmää silmukan sisällä, luodaan useita tehtäviä - yksi kutakin työn tai iteraation yksikköä kohti. Jos kuitenkin käytät Parallel.ForEach-toimintoa Task.Run-toiminnon sijasta silmukan sisällä, osioija luodaan välttääkseen luomasta enemmän tehtäviä toiminnan suorittamiseksi kuin sitä tarvitaan. Tämä voi parantaa suorituskykyä merkittävästi, koska voit välttää liian monta kontekstikytkintä ja silti hyödyntää useita ytimiä järjestelmässäsi.

On huomattava, että Parallel.ForEach käyttää Partitioneria sisäisesti jakamaan kokoelman työtehtäviin. Muuten, tämä jakelu ei tapahdu kullekin nimikeluettelon tehtävälle, vaan se tapahtuu eränä. Tämä vähentää mukana olevia yleiskustannuksia ja parantaa siten suorituskykyä. Toisin sanoen, jos käytät Task.Run tai Task.Factory.StartNew silmukan sisällä, ne luovat uusia tehtäviä nimenomaisesti kullekin silmukan iteraatiolle. Parallel.ForEach on paljon tehokkaampi, koska se optimoi suorituksen jakamalla työmäärän järjestelmän useille ytimille.