2012-05-30 16 views
21

En C# con CTP asíncrono o de la beta vs.net 2011 podemos escribir código recursivo de esta manera:¿La recursión asíncrona es segura en 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 
} 

En esta muestra específica, que espera el código asincrónicos para un socket TCP y una vez que ha sido aceptado, se recurrirá y sincronizará espera de otro.

Esto parece funcionar bien, ya que la sección de espera hará que el código regrese a la persona que llama y, por lo tanto, no cause un desbordamiento de la pila.

Así que dos preguntas aquí:

  1. si ignoramos el hecho de que estamos tratando con tomas en esta muestra. ¿Está bien hacer la recursión sin pila de esta manera? o hay inconvenientes que me falta?

  2. desde una perspectiva IO, ¿el código anterior sería suficiente para manejar todas las solicitudes entrantes? Quiero decir con solo esperar una, y una vez que sea aceptada, empiece a esperar otra. ¿Algunas solicitudes fallarán debido a esto de alguna manera?

+1

Así que cuando no 'manija (socket)' vez se ha quedado? – leppie

+2

No veo nada incorrecto en sí mismo, pero ¿qué le agrega al OMI más directo? Public async void AwaitSocket() {while (true) {var socket = await this.AcceptSocketAsync(); Manija (zócalo); }} '? – hvd

+0

@leppie Después de 'AwaitSocket();' regresa. Y sí, regresa. – hvd

Respuesta

2

De la discusión anterior, creo que algo así será el mejor enfoque. Por favor, dar retroalimentación

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

¿Qué sucede si 'AcceptSocketAsync()' o 'HandleAsync()' arroja una excepción? – svick

+0

Sí, ¿qué sucede si HandleAsync se lanza después de la parte de rendimiento aguardada? si la continuación se maneja en el grupo de subprocesos y el código arroja, esto terminará el hilo del grupo de subprocesos, ¿verdad? –

+1

Si se lanza una excepción desde 'async void', se pasa directamente al" contexto ". Si la continuación se está ejecutando en un contexto de grupo de subprocesos, esto provocará que se genere una excepción directamente en un subproceso del grupo de subprocesos, lo que bloqueará el proceso. Normalmente, debe hacer que todos los métodos 'async' devuelvan' Task'/'Task ' a menos que sean manejadores de eventos (y por lo tanto * must * be' void'). Piénselo de esta manera: 'async void' está * permitido *, no * recomendado *. –

Cuestiones relacionadas