2009-02-20 12 views
7

Pregunta rápida aquí: ¿hay algún beneficio obvio para usar comunicación asincrónica con la clase NetworkStream (generada por TcpClient), es decir, los métodos BeginRead/BeginWrite en lugar de ejecutar un hilo separado y usar operaciones síncronas en ese , es decir, ¿leer/escribir? Mi impresión ha sido (podría ser bastante erróneo) que las operaciones asíncronas no sean de bloqueo y se realicen a nivel del sistema operativo (¿quizás en la pila TCP?), Con un elemento del grupo de subprocesos para la devolución de llamada. Estoy pensando que seguramente debe ser diferente de llamar a ThreadPool.QueueUserWorkItem en el método sincrónico, o que tendría poco sentido proporcionarlo. Ahora, estoy bastante seguro de que este es el tipo de cosas (llamadas a nivel de sistema operativo) que ocurre al menos para la E/S de archivos, pero si alguien pudiera aclarar el asunto con respecto a la comunicación de red (TCP), sería de gran ayuda. Básicamente, me gustaría saber si hay algún beneficio específico para cualquiera de los métodos (además del obvio de poder usar las clases BinaryReader/StreamReader con las llamadas sincrónicas).Comunicación TCP asíncrona en .NET

Respuesta

10

Existe una diferencia, si usa un subproceso Worker para llamar a la versión síncrona, vinculará uno de los subprocesos en una llamada de bloqueo.

Mientras que los métodos Begin no atarán un hilo sino que usarán una devolución de llamada en una señal de E/S apropiada, la devolución de llamada se ejecutará en un hilo del grupo.

+0

Bien, esto es más o menos exactamente lo que sospechaba. Entonces, ¿recomendaría usar los métodos Begin en lugar de los métodos síncronos en un hilo separado, cuando sea posible? Parecería más elegante, si no más eficiente, hacerlo de esta manera. – Noldorin

+2

. La implementación de .NET framework de bajo nivel (BeingXX/EndXX) generalmente usa puertos IO Completion. Este es el enfoque IO más escalable disponible en Windows. – Richard

+0

@Noldorin: Sí, recomendaría usar Begin Methods principalmente porque el código es más simple de esa manera, felizmente en este caso, el enfoque más simple también es más eficiente. – AnthonyWJones

1

Como han señalado otros, la asignación de otro subproceso a su proceso le afectará cuando use el método síncrono a medida que aumenta el número de conexiones simultáneas.

Sin embargo, si sabes que solo tendrás un pequeño número de conexiones, diría que se convierte en un lavado y debes elegir el método más natural para tu aplicación.

En el caso donde la sobrecarga del hilo es insignificante, esperaría que los dos escenarios se desarrollaran de esta manera.

asíncrono:

  1. Haces llamada a BeginRead/BeginWrite
  2. "El sistema" (marco/OS) se informa de lo que quiere
  3. lectura/escritura completa
  4. " El sistema "le dice a un hilo en el grupo de subprocesos que llame a su devolución de llamada
  5. Haga lo que tenga que hacer para completar la operación

síncrono en otro hilo:

  1. Usted recibe un hilo desde el grupo de subprocesos para manejar la IO
  2. Usted hace la llamada para leer/escribir
  3. "El sistema" (marco/OS) está informado de lo que quiere
  4. Lectura/Escritura completa
  5. Hace lo que tenga que hacer para completar la operación

La única diferencia aquí es que el paso 4 de la llamada asincrónica se convierte en el paso 1 en el caso síncrono en otro hilo.

+0

Sí, esta fue básicamente mi otra consideración. Hrmm, ahora tengo las mismas dos vistas opuestas con las que comencé ... – Noldorin

+1

Un hilo, incluso si está bloqueado, es una pieza importante de recursos (comenzando con 1MB de espacio de pila asignado desde el espacio VM del proceso). – Richard

+0

Compraré eso hasta cierto punto, pero ya que estamos hablando de quitar un hilo del grupo aquí, no sé si importa mucho. Mi inclinación sería hacer lo que sea más natural para la aplicación a menos que pueda probar que tuve un problema. Optimización prematura y todos ... –

1

Estoy de acuerdo con AnthonyWJones, imagine que su grupo de subprocesos tiene 10 subprocesos, pero tiene 100 clientes con suficiente pasivo. Con las llamadas asincrónicas, puede comenzar con ReadRead para cada una de ellas, y cuando los datos de alguien estén listos, serán procesados ​​por uno de los subprocesos del grupo. Pero si intenta utilizar QueueUserWorkItem, programará la recepción de datos de solo 10 clientes. Y si no envían nada en 1 hora, otros 90 clientes nunca tendrán la oportunidad de obtener datos.

+0

De hecho, veo que llamar al método Begin claramente no es equivalente a QueueUserItmem ahora ... Aún así, el punto principal es cómo se compara con ejecutar un hilo separado con operaciones sincrónicas. – Noldorin

+0

No hay gran diferencia si usa explícitamente subprocesos de un grupo o si crea un número de subprocesos usted mismo, de cualquier forma que tenga un número limitado de subprocesos ... Con Async ops, los subprocesos se usan solo para hacer el trabajo real, y luego lanzado. Con Sync ops, los hilos pueden ser bloqueados por espera inactiva. – alex2k8

+0

Ok, eso tiene sentido ahora. Gracias por las explicaciones. – Noldorin

1

No estoy muy seguro de por qué NetworkStream incluso tiene un BeginRead/Write, ya que esto básicamente infringe el propósito del NetworkStream en primer lugar. Al utilizar los métodos Async, obtienes una respuesta más rápida, una mayor escalabilidad y un consumo reducido de recursos.

Si solo va a tener una conexión a la vez, entonces no importa mucho si usa un hilo de grupo de subprocesos o no, pero si acepta muchas conexiones, entonces definitivamente desea utilizar async.

+0

Veo lo que quieres decir. Estos métodos asíncronos probablemente serían más adecuados dentro de la clase TcpClient. Parece que el consenso se inclina levemente hacia el uso de métodos asíncronos para un mejor rendimiento (aunque solo marginalmente). – Noldorin

Cuestiones relacionadas