2012-05-30 13 views
21

W języku C# z CTP asynchronicznym lub vs.net 2011 beta możemy napisać rekurencyjną kodu:Czy rekurencja asynchroniczna jest bezpieczna w języku C# (async ctp/.net 4.5)?

public async void AwaitSocket() 
{ 
    var socket = await this.AcceptSocketAsync(); //await socket and >>return<< to caller 
    AwaitSocket(); //recurse, note that the stack will never be deeper than 1 step since await returns.. 
    Handle(socket); // this will get called since "await" returns 
} 

W tej konkretnej próbki, czeka na kod async gniazda TCP i raz został on zaakceptowany, będzie się powtarzać i asynchronicznie czekać na kolejną.

Wygląda na to, że działa dobrze, ponieważ oczekująca sekcja sprawi, że kod wróci do wywołującego, a zatem nie spowoduje przepełnienia stosu.

Więc dwa pytania tutaj:

  1. jeśli pominiemy fakt, mamy do czynienia z gniazd w tej próbce. Czy można w ten sposób wykonywać rekurencję bez użycia sterty? czy są jakieś wady?

  2. z perspektywy IO, czy powyższy kod byłby wystarczający do obsłużenia wszystkich przychodzących żądań? Mam na myśli tylko czekanie na jeden, a gdy już zostanie przyjęty, zaczekaj na kolejną. Czy niektóre żądania zawiodą z tego powodu?

+1

Kiedy więc "Handle (socket)" kiedykolwiek działa? – leppie

+2

Nie widzę w tym nic złego per se, ale co to znaczy dodać do IMO bardziej prostego 'public async void AwaitSocket() {while (true) {var socket = czekaj na to.AcceptSocketAsync(); Uchwyt (gniazdo); }} '? – hvd

+0

@leppie Po 'AwaitSocket();' zwraca. I tak, wraca. – hvd

Odpowiedz

2

Z powyższej dyskusji, myślę, że coś takiego będzie najlepszym podejściem. Proszę przekazać opinię

public async void StartAcceptingSockets() 
{ 
    await Task.Yield(); 
    // return to caller so caller can start up other processes/agents 
    // TaskEx.Yield in async ctp , Task.Yield in .net 4.5 beta 

    while(true) 
    { 
     var socket = await this.AcceptSocketAsync(); 
     HandleAsync(socket); 
     //make handle call await Task.Yield to ensure the next socket is accepted as fast 
     //as possible and dont wait for the first socket to be completely handled 
    } 
} 

private async void HandleAsync(Socket socket) 
{ 
     await Task.Yield(); // return to caller 

     ... consume the socket here... 
} 
+0

Co się stanie, jeśli 'AcceptSocketAsync()' lub 'HandleAsync()' zgłasza wyjątek? – svick

+0

Tak, co stanie się exaclt, jeśli HandleAsync rzuca po oczekiwaniu część zysku? jeśli kontynuacja jest obsługiwana w wątku, a kod wyrzuca, spowoduje to przerwanie wątku puli wątków, prawda? –

+1

Jeśli wyjątek jest wyrzucany z 'async void', jest przekazywany bezpośrednio do" kontekstu ". Jeśli kontynuacja działa w kontekście puli wątków, spowoduje to, że wyjątek zostanie podniesiony bezpośrednio w wątku puli wątków, powodując awarię procesu. Zwykle powinieneś mieć wszystkie metody 'async' zwracające' Zadanie'/'Zadanie ', chyba że są one procedurami obsługi zdarzeń (i dlatego * muszą * być 'void'). Pomyśl o tym w ten sposób: 'async void' jest * dozwolone *, nie * zalecane *. –

Powiązane problemy