Vra

Ek het nie die verskillende tussen C # 's (en VB se) nuwe asinkroniseer funksies, en NET 4.0 se Taak Parallel Biblioteek . Neem, byvoorbeeld, Eric Lippert se kode hiervandaan :

async void ArchiveDocuments(List<Url> urls) {
    Task archive = null;
    for(int i = 0; i < urls.Count; ++i) {
        var document = await FetchAsync(urls[i]);
        if (archive != null)
            await archive;
        archive = ArchiveAsync(document);
    }
}

Dit blyk dat die await navraag dien twee verskillende doeleindes. Die eerste voorkoms (FetchAsync) blyk te beteken, "As hierdie waarde word gebruik later in die metode en sy taak is nog nie klaar nie, wag totdat dit voordat u verder gaan voltooi." die tweede geval (archive) blyk te beteken, "As hierdie taak nog nie klaar is, wag nou totdat dit voltooi." As ek verkeerd is, Korrigeer my .

Kan nie dit net so maklik geskryf soos hierdie?

void ArchiveDocuments(List<Url> urls) {
    for(int i = 0; i < urls.Count; ++i) {
        var document = FetchAsync(urls[i]);       // removed await
        if (archive != null)
            archive.Wait();                       // changed to .Wait()
        archive = ArchiveAsync(document.Result);  // added .Result
    }
}

Ek het die eerste await met 'n Task.Result waar die waarde werklik nodig is, en die tweede await met Task.Wait(), waar die wag eintlik plaasvind vervang. Die funksie is (1) reeds geïmplementeer, en (2) baie nader semanties na wat werklik gebeur in die kode.

Ek het besef dat 'n async metode is herskryf as 'n toestand masjien, soortgelyk aan iterators, maar ek weet ook nie sien watter voordele wat bring. Enige kode wat 'n ander draad vereis om te funksioneer (soos die aflaai) sal steeds vereis 'n ander draad, en enige kode wat dit nie doen nie (soos die lees van 'n lêer) kon nog gebruik maak van die TPL te werk met net 'n enkele draad.

Ek is natuurlik ontbreek iets groot hier; Kan iemand help my verstaan ??dit 'n bietjie beter?

Was dit nuttig?

Oplossing

Ek dink die misverstand ontstaan ??hier:

  

Dit blyk dat die Wag navraag dien twee verskillende doeleindes. Die eerste voorkoms (FetchAsync) blyk te beteken: "As hierdie waarde later gebruik word in die metode en sy taak is nog nie klaar nie, wag totdat dit voordat u verder gaan voltooi." Die tweede geval (argief) blyk te beteken: "As hierdie taak nog nie klaar is, wag nou totdat dit voltooi." As ek verkeerd is, moet asseblief korrigeer my.

Dit is eintlik heeltemal verkeerd. Beide van hulle het dieselfde betekenis.

In jou eerste geval:

var document = await FetchAsync(urls[i]);

Wat hier gebeur, is dat die runtime sê "Start roeping FetchAsync, dan terug die huidige uitvoering punt om die draad noem hierdie metode." Daar is geen "wag" hier - in plaas daarvan, uitvoering keer terug na die roeping sinchronisasie konteks, en dinge hou drukking. Op 'n sekere punt in die toekoms, sal FetchAsync se taak te voltooi, en op daardie stadium, sal hierdie kode te hervat op sinchronisasie konteks die roeping draad se, en die volgende stelling (toeken die dokument veranderlike) sal plaasvind.

Uitvoer sal dan voortgaan totdat die tweede Wag oproep - op watter tyd, sal dieselfde ding gebeur - as die Task<T> (argief) is nog nie voltooi nie, sal uitvoering vrygelaat word om die roeping konteks - anders sal die argief stel nie .

In die tweede geval, dinge is baie anders - hier, jy uitdruklik blokkeer, wat beteken dat die roeping sinchronisasie konteks nooit 'n kans om 'n kode uit te voer totdat jou hele metode voltooi het, sal kry. Toegestaan ??is, is daar nog asynchronie, maar die asynchronie is heeltemal vervat binne hierdie blok van kode -. Geen kode buite hierdie geplak kode sal gebeur op hierdie draad totdat al van jou kode completes

Ander wenke

Daar is 'n groot verskil:

Wait() blokke, await nie blokkeer. As jy die asinkroniseer weergawe van ArchiveDocuments() hardloop op jou GUI draad, sal die GUI reageer bly terwyl die haal en argivering bedrywighede loop. As jy die TPL weergawe met Wait() gebruik, sal jou GUI geblokkeer.

Let daarop dat async daarin slaag om dit te doen sonder om enige drade - by die punt van die await, beheer word eenvoudig terug na die boodskap lus. Sodra die taak wat wag vir voltooi, is die res van die metode (voortsetting) waglys op die boodskap lus en die GUI draad sal voortgaan hardloop ArchiveDocuments waar dit opgehou het.

Anders gekook dit neer op 'n baie bondige antwoord in die Channel 9 live onderhoud wat hy gedoen het. Ek raai dit

Die nuwe A-sinkroniseer en wag vir sleutelwoorde kan jy orkestreer concurrency in jou programme. Hulle het nie werklik bekend te stel enige concurrency in jou aansoek.

TPL en meer spesifiek Taak is een manier wat jy kan gebruik om werklik uit te voer bedrywighede gelyktydig. Die nuwe asinkroniseer en wag vir navraag toelaat om komponeer hierdie konkurrente bedrywighede in 'n "sinchrone" of "lineêre" mode.

Jy kan dus steeds skryf 'n lineêre vloei van beheer in jou programme, terwyl die werklike rekenaar mag of nie mag nie gelyktydig gebeur. Wanneer berekening beteken gelyktydig gebeur nie, wag en asinkroniseer toelaat om komponeer hierdie bedrywighede.

Die vermoë om die program vloei van beheer te draai in 'n toestand masjien is wat hierdie nuwe sleutelwoorde interessante. Dink aan dit as opbrengs beheer , eerder as waardes.

Kyk bietjie na hierdie Channel 9 video van Anders praat die nuwe funksie.

Die probleem hier is dat die handtekening van ArchiveDocuments is misleidend. Dit het 'n eksplisiete terugkeer van void maar regtig die terugkeer is Task. Om my nietig impliseer sinchrone want daar is geen manier om te "wag" vir dit om klaar te maak. Oorweeg die alternatiewe handtekening van die funksie.

async Task ArchiveDocuments(List<Url> urls) { 
  ...
}

Vir my wanneer dit geskryf op hierdie manier die verskil is veel meer voor die hand liggend. Die ArchiveDocuments funksie is nie een wat sinkronies voltooi, maar sal later voltooi.

Die oproep om FetchAsync() sal nog blokkeer totdat dit voltooi (tensy 'n verklaring binne oproepe await?) Die sleutel is dat beheer word teruggekeer na die oproeper (omdat die ArchiveDocuments metode self as async verklaar). So die oproeper gelukkig kan verder verwerk UI logika, reageer op gebeure, ens

Wanneer FetchAsync() completes, dit onderbreek die oproeper aan die lus te voltooi. Dit tref ArchiveAsync() en blokke, maar ArchiveAsync() waarskynlik net 'n nuwe taak, begin dit, en die taak terugkeer. Dit laat die tweede lus om te begin, terwyl die taak is die verwerking van.

Die tweede lus treffers FetchAsync() en blokke, terugkeer beheer relevant tot die oproeper. Wanneer FetchAsync() completes, dit weer onderbreek die oproeper om voort te gaan verwerk. Dit tref dan await archive, wat opbrengste te beheer om die oproeper totdat die Task geskep in lus 1 afgehandel het. Sodra die taak voltooi is, is die oproeper weer onderbreek, en die tweede rondte doen 'n beroep ArchiveAsync(), wat 'n begin taak kry en begin loop 3, herhaal ad nauseum .

Die sleutel is die terugkeer van beheer aan die oproeper terwyl die swaar zuigheffers is die uitvoering.

Die Wag navraag nie bekend concurrency. Dit is soos die opbrengs navraag, dit vertel die samesteller te herstruktureer jou kode in lambda beheer word deur 'n staat masjien.

Om te sien watter Wag kode soos sou lyk sonder 'Wag' sien hierdie uitstekende skakel: http://blogs.msdn.com/b/windowsappdev/archive/2012/04/24/diving-deep-with-winrt-and-await Aspx

Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top