2012-01-07 17 views
74

Czy ktoś mógłby być na tyle uprzejmy, aby potwierdzić, czy poprawnie zrozumiałem słowo kluczowe Async? (Używając wersji 3 CTP)Czy Async czeka na odpowiednik słowa kluczowego ContinueWith lambda?

Do tej pory doszedłem do wniosku, że wstawienie słowa kluczowego oczekującego przed wywołaniem metody zasadniczo powoduje 2 rzeczy, A. Tworzy natychmiastowy powrót i B. Tworzy "kontynuację", która jest wywoływana po zakończeniu wywołania metody asynchronicznej. W każdym razie kontynuacja jest pozostałą częścią bloku kodu dla metody.

Więc zastanawiam się, czy te dwa bity kodu są równoważne pod względem technicznym, a jeśli tak, czy to w zasadzie oznacza, że ​​oczekiwane słowo kluczowe jest identyczne z tworzeniem ContinueWith Lambda (np. Jest to skrót kompilatora dla jednego) ? Jeśli nie, jakie są różnice?

bool Success = 
    await new POP3Connector(
     "mail.server.com", txtUsername.Text, txtPassword.Text).Connect(); 
// At this point the method will return and following code will 
// only be invoked when the operation is complete(?) 
MessageBox.Show(Success ? "Logged In" : "Wrong password"); 

VS

(new POP3Connector(
    "mail.server.com", txtUsername.Text, txtPassword.Text).Connect()) 
.ContinueWith((success) => 
    MessageBox.Show(success.Result ? "Logged In" : "Wrong password")); 

Odpowiedz

73

Ogólna idea jest poprawna - pozostała część wykonana jest metodą do kontynuacji rodzaju.

Szczegółowe informacje na temat transformacji kompilatora async/await znajdują się na stronie "fast path" blog post.

Różnice, u mojej głowie:

await kluczowe również korzysta się z „kontekstu” koncepcji planowania. Kontekst planowania ma wartość SynchronizationContext.Current, jeśli istnieje, czyli cofa się na TaskScheduler.Current. Kontynuacja jest następnie uruchamiana w kontekście planowania. Tak więc przybliżeniem byłoby przejście TaskScheduler.FromCurrentSynchronizationContext do ContinueWith, w razie potrzeby cofając się na TaskScheduler.Current.

Rzeczywista implementacja async/await opiera się na dopasowywaniu wzorców; używa "wyczekiwanego" wzoru, który pozwala na inne rzeczy oprócz zadań oczekiwanych. Niektóre przykłady to asynchroniczne interfejsy użytkownika WinRT, niektóre specjalne metody, takie jak Yield, obserwowalne Rx i special socket awaitables that don't hit the GC as hard. Zadania są potężne, ale nie są jedynymi oczekiwaniami.

Jeszcze jedna drobna różnica nitpicky przychodzi na myśl: jeśli oczekiwanie jest już zakończone, wówczas metoda async faktycznie nie powróci w tym momencie; kontynuuje synchronicznie. Jest to jakby przejście od TaskContinuationOptions.ExecuteSynchronously, ale bez problemów związanych ze stosem.

+2

bardzo dobrze powiedziane - staram się odkładać na posty Jona, ponieważ są one o wiele bardziej rozbudowane niż cokolwiek, co miałbym czas na odpowiedź na SO, ale Stephen ma absolutną rację. WRT, co jest godne uwagi (a zwłaszcza GetAwaiter), jego post # 3 jest bardzo pomocny IMHO :) http://msmvps.com/blogs/jon_skeet/archive/2011/05/13/eduasync-part-3-the-shape- metody-async-awaitable-boundary.aspx –

+4

Miejsce Stephena na miejscu. Dla prostych przykładów łatwo pomyśleć, że async/await to skrót do ContinueWith - jednak lubię myśleć o tym na odwrocie. Async/await jest w rzeczywistości silniejszym wyrażeniem tego, do czego używałeś ContinueWith. Problem polega na tym, że ContinueWith (...) używa lambdas i pozwala na przeniesienie wykonania do kontynuacji, ale inne koncepcje sterowania, takie jak pętle, są całkiem niemożliwe, jeśli musisz umieścić połowę ciała pętli przed ContinueWith (.. .) a druga połowa po. Kończy się ręcznym łańcuchem kontynuacji. –

+7

Kolejny przykład, w którym async/await jest znacznie bardziej ekspresyjny niż ContinueWith (...) przepływa przez wyjątki. Możesz oczekiwać wiele razy w tym samym bloku try, a dla każdego etapu wykonania, ich wyjątki mogą być kierowane do tego samego bloku catch (...) bez konieczności pisania ton kodu, który robi to jawnie. –

8

To "zasadniczo", ale wygenerowany kod robi dokładnie więcej niż tylko to. W przypadku partii bardziej szczegółowo na wygenerowany kod, bardzo polecam Jon Skeet za Eduasync serii:

http://codeblog.jonskeet.uk/category/eduasync/

W szczególności, po 7 dostaje się to, co zostanie wygenerowany (jak CTP 2) i dlaczego, więc prawdopodobnie idealnie pasuje do tego, co szukasz w tej chwili:

http://codeblog.jonskeet.uk/2011/05/20/eduasync-part-7-generated-code-from-a-simple-async-method/

EDIT: Myślę, że to może być bardziej szczegółowo niż co szukasz od kwestii, ale jeśli zastanawiasz jakie rzeczy wyglądają, gdy masz wiele czekania w metodzie, o czym mówi post # 9 :)

http://codeblog.jonskeet.uk/2011/05/30/eduasync-part-9-generated-code-for-multiple-awaits/