2012-05-30 10 views
21

In C# mit Asynchron-CtP oder vs.net 2011 Beta können wir rekursive Code wie folgt schreiben:Ist asynchrone Rekursion in C# sicher (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 
} 

In diesem speziellen Probe, die Code-Asynchron wartet auf eine TCP-Socket und sobald es angenommen wurde, es wird rekursiv und asynchron auf einen anderen warten.

Dies scheint gut zu funktionieren, da der Abschnitt warten den Code zurück zum Aufrufer und damit keinen Stapelüberlauf verursachen wird.

So zwei Fragen hier:

  1. , wenn wir die Tatsache, dass wir es zu tun haben mit Steckdosen in dieser Probe zu ignorieren. Ist es in Ordnung, die Stapelfreie Rekursion auf diese Weise durchzuführen? oder gibt es Nachteile Ich vermisse?

  2. aus einer IO-Perspektive würde der obige Code genug sein, um alle eingehenden Anfragen zu behandeln? Ich meine, indem ich nur auf eins warte, und sobald es akzeptiert wird, fange an, auf einen anderen zu warten. Scheitern einige Anfragen irgendwie?

+1

Also wann läuft 'Handle (Socket)' jemals? – leppie

+2

Ich sehe nichts falsches an sich, aber was fügt es dem IMO einfacher hinzu? Public async void AwaitSocket() {while (wahr) {var socket = away this.AcceptSocketAsync(); Griff (Steckdose); }} '? – hvd

+0

@leppie Nach 'AwaitSocket();' kehrt zurück. Und ja, es kommt zurück. – hvd

Antwort

2

Aus der obigen Diskussion, ich denke, so etwas wird der beste Ansatz sein. Bitte geben Sie eine Rückmeldung

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

Was passiert, wenn 'AcceptSocketAsync()' oder 'HandleAsync()' eine Ausnahme auslöst? – svick

+0

Ja, was passiert exaclt, wenn HandleAsync nach dem abwarten Yield-Teil wirft? Wenn die Fortsetzung im Threadpool behandelt wird und der Code wirft, wird der Threadpool-Thread beendet, richtig? –

+1

Wenn eine Ausnahme von 'async void' ausgelöst wird, wird sie direkt an den" Kontext "übergeben. Wenn die Fortsetzung in einem Thread-Pool-Kontext ausgeführt wird, führt dies dazu, dass direkt in einem Thread-Pool-Thread eine Ausnahme ausgelöst wird, die den Prozess zum Absturz bringt. Normalerweise sollten alle 'async' Methoden' Task'/'Task ' zurückgeben, es sei denn, sie sind Event-Handler (und daher * muss * 'void' sein). Stellen Sie es sich so vor: 'async void' ist * erlaubt *, nicht * empfohlen *. –