2011-06-22 26 views
5

Mam około 15 minut do mojej pierwszej gry z async CTP ... (nice).async ctp rekurencja

Oto bardzo prosty serwer mam sklecone:

internal class Server 
{ 
    private HttpListener listener; 
    public Server() 
    { 
     listener = new HttpListener(); 
     listener.Prefixes.Add("http://*:80/asynctest/"); 
     listener.Start(); 
     Go(); 
    } 

    async void Go() 
    { 
     HttpListenerContext context = await listener.GetContextAsync(); 
     Go(); 
     using (var httpListenerResponse = context.Response) 
     using (var outputStream = httpListenerResponse.OutputStream) 
     using (var sw = new StreamWriter(outputStream)) 
     { 
      await sw.WriteAsync("hello world"); 
     } 
    } 
} 

Jak widać, sposób asynchroniczny Go nazywa siebie. W klasycznym niezsynchronizowanym świecie spowodowałoby to przepełnienie stosu. Zakładam, że tak nie jest w przypadku metody asynchronicznej, ale chciałbym być pewien, tak czy inaczej. Ktoś?

Odpowiedz

13

Złammy go do czegoś prostszego:

async static void Go() 
{ 
    await Something(); 
    Go(); 
    await SomethingElse(); 
} 

Jak radzi sobie z tym kompilator?

Zasadniczo ten staje się coś takiego szkicu:

class HelperClass 
{ 
    private State state = STARTSTATE; 
    public void DoIt() 
    { 

     if (state == STARTSTATE) goto START; 
     if (state == AFTERSOMETHINGSTATE) goto AFTERSOMETHING; 
     if (state == AFTERSOMETHINGELSESTATE) goto AFTERSOMETHINGELSE; 

     START: 
     { 
      state = AFTERSOMETHINGSTATE; 
      var awaiter = Something().MakeAnAwaiter(); 
      awaiter.WhenDoneDo(DoIt); 
      return; 
     } 

     AFTERSOMETHING: 
     { 
      Go(); 
      state = AFTERSOMETHINGELSESTATE; 
      var awaiter = SomethingElse().MakeAnAwaiter(); 
      awaiter.WhenDoneDo(DoIt); 
      return; 
     } 

     AFTERSOMETHINGELSE: 

     return; 
    } 

    static void Go() 
    { 
     var helper = new HelperClass(); 
     helper.DoIt(); 
    } 

Teraz trzeba pamiętać, jest to, że gdy każda operacja asynchroniczna kończy „ZrobTo” ma zostać ponownie wywołany przez pętlę komunikatów (na odpowiednim przykład helpera oczywiście).

Co się dzieje? Rozwiąż to. Dzwonisz do Go po raz pierwszy. To sprawia, że ​​pomocnik numer jeden i wzywa DoIt. To wywołuje funkcję Coś(), odzyskuje zadanie, oczekuje na to zadanie, informuje osobę oczekującą "kiedy skończysz, zadzwoń do helper1.DoIt" i zwróci.

Dziesiąta sekundy później zadanie zostaje zakończone, a pętla wiadomości wywołuje DoIt helper1. stan helper1 to AFTERSOMETHINGSTATE, więc bierzemy goto i wołamy Go. To sprawia, że ​​helper2 i dzwoni DoIt na ten temat. To wywołuje funkcję Something(), odsyła zadanie, sprawia, że ​​oczekujesz na to zadanie, mówi osobie oczekującej "kiedy skończysz, zadzwoń do DoIt na helper2" i zwróć kontrolę do DoIt helper1. To wywołuje SomethingElse, sprawia, że ​​oczekujesz na to zadanie i mówi: "kiedy skończysz robić coś innego, zadzwoń do DoIt helper1. Następnie wraca.

Teraz mamy dwa zadania wyjątkowe i żaden kod na stosie. Jedno z zadań zostanie ukończone jako pierwsze. Załóżmy, że zadanie SomethingElse zakończyło się jako pierwsze. Pętla komunikatów wywołuje funkcję helper1.DoIt(), która natychmiast zwraca wartość. Helper1 jest teraz śmieciem.

Później pętla komunikatów wywołuje funkcję helper2.DoIt() i rozgałęzia się na AFTERSOMETHING. Teraz wywoływana jest funkcja Go(), która tworzy helper3 ...

Więc nie, nie ma tutaj nieograniczonej rekursji. Za każdym razem, gdy Go wykonuje, działa aż do asynchronicznego uruchamiania Coś(), a następnie wraca do swojego wywołującego. Wezwanie do rzeczy po "coś" dzieje się później. "Go" jest tylko na stosie tylko raz.

+0

Dobrze. Podejrzewałem tak samo, ale dobrze jest zobaczyć szczegóły mechaniki konstruktu. Dzięki za tak wyczerpującą odpowiedź (jak zwykle!). – spender

+0

@spender: Nie ma za co! Ciesz się CTP, a jeśli masz pytania, uwagi, obawy, pochwały, konstruktywną krytykę itd., Opublikuj je na Forum Async CTP. Mamy kierowników programów, którzy czytają to codziennie i zbierają opinie użytkowników na temat funkcji, która jest dla nas bardzo pomocna. –