2011-09-19 11 views
6

Tratando de averiguar si debería o no utilizar métodos asincrónicos o no, tales como:¿Es necesario utilizar los métodos async Begin/End si ya están en una secuencia separada?

y

a diferencia de sus versiones síncronas TcpListener.AcceptTcpClient y NetworkStream.Read. He estado buscando hilos relacionados pero todavía estoy un poco inseguro sobre una cosa:

Pregunta: La principal ventaja de utilizar un método asincrónico es que la GUI no está bloqueada. Sin embargo, estos métodos serán llamados en hilos Task por separado, por lo que no hay ninguna amenaza de eso. Además, TcpListener.AcceptTcpClient bloquea el hilo hasta que se realice una conexión para que no se desperdicien los ciclos de la CPU. Dado que este es el caso, ¿por qué tantos siempre recomiendan usar las versiones asíncronas? Parece que en este caso las versiones sincrónicas serían superiores?

Además, otra desventaja del uso de métodos asíncronos es la mayor complejidad y el constante vaciado de objetos. Por ejemplo, tener que hacer esto:

private void SomeMethod() 
{ 
    // ... 

    listener.BeginAcceptTcpClient(OnAcceptConnection, listener); 
} 

private void OnAcceptConnection(IAsyncResult asyn) 
{ 
    TcpListener listener = (TcpListener)asyn.AsyncState; 

    TcpClient client = listener.EndAcceptTcpClient(asyn); 
} 

En oposición a esto:

TcpClient client = listener.AcceptTcpClient();

También parece que las versiones asíncronas tendrían mucha más sobrecarga debido a tener que crear otro hilo. (Básicamente, cada conexión tendría un hilo y luego al leer ese hilo también tendría otro hilo. Threadception!)

Además, está el boxeo y el desempaquetado del TcpListener y la sobrecarga asociada a la creación, administración y cierre estos hilos adicionales.

Básicamente, donde normalmente solo habría subprocesos individuales para manejar conexiones de cliente individuales, ahora hay eso y luego un subproceso adicional para cada tipo de operación realizada (leer/escribir datos de secuencia y escuchar nuevas conexiones en el extremo del servidor)

Corrígeme si me equivoco. Todavía soy nuevo en el roscado y estoy tratando de entender todo esto. Sin embargo, en este caso, parece que usar los métodos síncronos normales y simplemente bloquear el hilo sería la solución óptima.

Respuesta

4

TcpListener.AcceptTcpClient bloquea el hilo hasta que se realice una conexión para que no se desperdicien los ciclos de la CPU.

Pero tampoco hay trabajo que hacer. Un Thread es un objeto de sistema operativo muy caro, más o menos caro. Su programa está consumiendo un megabyte de memoria sin que se use mientras el hilo se bloquea en la solicitud de conexión.

Sin embargo, estos métodos serán llamados en las roscas de tareas separadas a medida que se lo que no hay amenaza de que

Una tarea no es una buena solución ya sea, se utiliza un hilo de subprocesos pero el hilo bloqueará El administrador de subprocesos trata de mantener la cantidad de subprocesos de TP en ejecución igual al número de núcleos de CPU en la máquina. Eso no funcionará bien cuando un hilo TP se bloquea durante un tiempo prolongado. Impide que otros hilos de trabajo que están esperando su turno hagan otros trabajos útiles.

BeginAcceptTcpClient() utiliza la denominada devolución de llamada de finalización de E/S. No se consumen recursos del sistema mientras el socket está escuchando. Tan pronto como aparece una solicitud de conexión, el sistema operativo ejecuta una APC (llamada de procedimiento asíncrono) que toma un hilo de subproceso para hacer la devolución de llamada. El hilo en sí está en uso, por lo general, unos pocos microsegundos. Muy eficiente.

Este tipo de código va mucho más simple en la próxima versión de C# con el siguiente asíncrono y esperan palabras clave. Fin de año, tal vez.

3

Si llama a AcceptTcpClient() en cualquier hilo, ese hilo es inútil hasta que obtenga una conexión.

Si llama al BeginAcceptTcpClient(), el hilo de llamada puede detenerse inmediatamente, sin desperdiciar el hilo.

Esto es especialmente importante cuando se usa ThreadPool (o TPL), ya que utilizan una cantidad limitada de subprocesos de grupo.
Si tiene demasiados subprocesos esperando operaciones, puede quedarse sin subprocesos de subprocesos, por lo que los nuevos elementos de trabajo tendrán que esperar hasta que finalice uno de los otros subprocesos.

Cuestiones relacionadas