Vra

Ek het na aanleiding van die nuwe aankondiging met betrekking tot die nuwe async funksie wat sal wees in c # 5.0. Ek het 'n basiese begrip van voortsetting verby styl en van die transformasie van die nuwe c # samesteller maak om kode soos hierdie brokkie uit Eric Lippert se post :

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

Ek weet dat sommige tale te implementeer voortsettings native, via call-by-huidige-voortsetting (callcc), maar ek het nie regtig verstaan ??hoe dit werk of wat dit presies beteken.

So hier is die vraag: as Anders et al. het besluit om die bullet te byt en net te implementeer callcc in c # 5.0 in plaas van die async / await spesiale geval, wat sou die bogenoemde uittreksel lyk?

Was dit nuttig?

Oplossing

Original antwoord:

Jou vraag, soos ek dit verstaan, is "what if in plaas van die implementering van" Wag "spesifiek vir taakgebaseerde asynchronie, eerder, hoe meer algemene beheer vloei werking van die oproep-met-huidige-voortsetting in werking gestel het?"

Wel, in die eerste plek kom ons dink oor wat "Wag" doen. "Wag" neem 'n uitdrukking van tipe Task<T>, kry 'n awaiter, en doen 'n beroep die awaiter met die huidige voortsetting:

await FooAsync()

word effektief

var task = FooAsync();
var awaiter = task.GetAwaiter();
awaiter.BeginAwait(somehow get the current continuation);

Nou dink ons ??het 'n operateur callcc wat 'n metode neem as sy argument, en noem die metode met die huidige voortsetting. Dit sou lyk:

var task = FooAsync();
var awaiter = task.GetAwaiter();
callcc awaiter.BeginAwait;

Met ander woorde:

await FooAsync()

is niks meer as '

callcc FooAsync().GetAwaiter().BeginAwait;

Is dit jou vraag beantwoord?


Update # 1:

As 'n opmerkings wys daarop, die antwoord in die blokkie aanvaar die kodegenerasie patroon van die "Tegnologie Preview" weergawe van die asinkroniseer / Wag funksie. Ons het eintlik genereer effens anders kode in die beta version van die funksie, alhoewel logies Dit is dieselfde. Die huidige codegen is iets soos:

var task = FooAsync();
var awaiter = task.GetAwaiter();
if (!awaiter.IsCompleted)
{
    awaiter.OnCompleted(somehow get the current continuation);
    // control now returns to the caller; when the task is complete control resumes...
}
// ... here:
result = awaiter.GetResult();
// And now the task builder for the current method is updated with the result.

Let daarop dat hierdie is 'n bietjie meer ingewikkeld, en hanteer die geval waar jy "wag" 'n gevolg wat reeds bereken. Daar is geen behoefte om te gaan deur al die rigamarole van opbrengs beheer relevant tot die oproeper en die optel van weer waar jy opgehou het as die gevolg dat jy wag vir is in werklikheid reeds in die geheue kas vir jou reg daar.

So het die verband tussen "Wag" en "callcc" is nie heeltemal so eenvoudig soos dit was in die voorlopige weergawe, maar dit is nog steeds duidelik dat ons in wese is besig met 'n callcc op die "OnCompleted" metode van die awaiter. Ons het net nie die callcc doen as ons nie hoef te.


Update # 2:

As hierdie antwoord

https://stackoverflow.com/a/9826822/88656

van Timwi wys daarop, die semantiek van die oproep / cc en wag vir is nie heeltemal dieselfde; 'n "ware" oproep / cc vereis óf dat ons "vang" die entire voortsetting van 'n metode insluitend sy hele oproep stapel , of anders gestel dat die hele program herskryf in voortsetting verbygaande styl.

Die "Wag" funksie is meer soos 'n "koöperatiewe oproep / cc"; die voortsetting net vang "wat is die huidige -taak terugkeer metode oor om volgende te doen by die punt van die Wag?" As die oproeper van die taak terugkeer metode gaan iets interessant doen nadat die taak voltooi is, dan is dit gratis om aan te meld die voortsetting daarvan as die voortsetting van die taak.

Ander wenke

Ek is geen kenner op voortsettings, maar ek sal 'n steek te neem aan die verduideliking van die verskil tussen asinkroniseer / Wag en oproep / cc. Natuurlik hierdie verduideliking aanvaar ek verstaan ??oproep / cc en asinkroniseer / Wag, wat Ek is nie seker of ek doen. Nietemin, hier gaan ...

Met C # 'asinkroniseer', jy vertel die samesteller 'n spesiale weergawe van daardie spesifieke metode wat verstaan ??hoe om dit te se toestand bottel in 'n hoop-data-struktuur te genereer, sodat dit kan word "uit die werklike stapel" en later hervat. Binne 'n asinkroniseer-konteks, "Wag" is dan soos "oproep / cc" in die sin dat dit gebruik die-samesteller gegenereer voorwerpe te bottel up die staat en stap uit die "regte stapel" totdat die taak afgehandel het. Maar, want dit is die samesteller herskryf van 'n asinkroniseer-metode wat die staat toelaat om gebottel te nie, wag kan slegs gebruik word in 'n asinkroniseer konteks.

In die eerste-klas oproep / cc, die taal runtime genereer al code sodanig dat die huidige voortsetting up kan word gebottel in 'n oproep-voortsetting-funksie (die maak van die asinkroniseer navraag onnodige). oproep / cc tree steeds soos wag nie, wat veroorsaak dat die huidige-voortsetting staat (dink aan die stapel staat) tot word botled en geslaag in as 'n funksie om die geroep-funksie. Een manier om dit te doen, is om hoop-rame vir alle funksie aanroeping, in plaas van 'n stapel 'rame gebruik. (Soms na verwys as 'stackless', soos in 'stackless luislang' of baie skema implementasies) Nog 'n manier is om al die data van die "regte stapel" en dinge dit op 'n hoop data-struktuur te verwyder voordat hy die oproep / cc teiken .

Sommige moeilike kwessies kan ontstaan ??as daar oproepe na eksterne funksies (dink DllImport) vermeng op die stapel. Ek vermoed dit is die rede waarom hulle het saam met die asinkroniseer / Wag implementering.

http://www.madore.org/~david/computers/callcc. html


As gevolg in C #, 'n funksie moet as "asinkroniseer" ten einde hierdie meganika gebruik gemerk, ek wonder of dit asinkroniseer navraag 'n virus sal word wat versprei na baie funksies in baie biblioteke. As dit gebeur. hulle kan uiteindelik besef hulle moet die eerste-klas oproep / cc by die VM vlak te implementeer, in plaas van hierdie samesteller-herskryf gebaseer asinkroniseer model. Net die tyd sal leer. Maar dit is beslis 'n nuttige hulpmiddel in die konteks van die huidige C # omgewing.

Kinda nutteloos sou ek sê. Skema tolke dikwels implementeer oproep / cc met 'n toestand masjien wat vang plaaslike staat op die wal. Wat presies wat C # 5.0 (of meer korrek C # 2,0 se iterator) doen as goed. Hulle het implementeer oproep / cc, die onttrekking hulle het met heel elegant.

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