traduccion thread example createthread create winapi io crystal-reports io-completion-ports

winapi - example - create thread traduccion



E/S superpuesta de Win32: ¿rutinas de finalización o WaitForMultipleObjects? (6)

Cualquiera de las dos rutinas funciona y realmente no creo que una sea significativa más rápido que otra.

Estos dos enfoques existen para satisfacer diferentes modelos de programación. WaitForMultipleObjects está ahí para facilitar el patrón de finalización asíncrono (como la función de selección () de UNIX), mientras que los puertos de finalización son más hacia el modelo impulsado por eventos.

Personalmente creo que el enfoque de WaitForMultipleObjects () resulta en un código más limpio y más seguro para subprocesos.

Me pregunto qué enfoque es más rápido y por qué?

Al escribir en un servidor Win32, he leído mucho sobre los puertos de finalización y la E / S superpuesta, pero no he leído nada que sugiera qué conjunto de API produce los mejores resultados en el servidor.

¿Debo usar rutinas de finalización o debo usar la API WaitForMultipleObjects y por qué?


En la Tabla 6-3 del libro Programación de red para Microsoft Windows, 2ª edición, se compara la escalabilidad de las E / S superpuestas a través de los puertos de finalización frente a otras técnicas. Los puertos de finalización eliminan el agua de todos los demás modelos de E / S cuando se trata de rendimiento, mientras se usan muchos menos hilos.


La diferencia entre WaitForMultipleObjects () y los puertos de finalización de E / S es que IOCP se escala a miles de objetos, mientras que WFMO () no se usa y no se debe usar para nada más que 64 objetos (aunque se pueda).

Realmente no se pueden comparar por rendimiento, porque en el dominio de <64 objetos, serán esencialmente idénticos.

Sin embargo, WFMO () realiza un round-robin en sus objetos, por lo que los objetos ocupados con números de índice bajos pueden matar a los objetos con números de índice altos. (Por ejemplo, si el objeto 0 se apaga constantemente, hará que los objetos 1, 2, 3, etc. se mueran de hambre). Esto es obviamente indeseable.

Escribí una biblioteca IOCP (para sockets) para resolver el problema C10K y ponerlo en el dominio público. Pude en una máquina W2K de 512 mb obtener 4,000 sockets que transfieren datos simultáneamente. (Puede obtener muchos más sockets, si están inactivos: un socket ocupado consume más pool no paginado y ese es el límite máximo de cuántos sockets puede tener).

http://www.45mercystreet.com/computing/libiocp/index.html

La API debe darle exactamente lo que necesita.


No es seguro. Pero yo uso WaitForMultipleObjects y / o WaitFoSingleObjects. Es muy conveniente.


Sugiere dos métodos de hacer E / S superpuestas e ignora el tercero (o malinterpreto su pregunta).

Cuando emite una operación superpuesta, un WSARecv() por ejemplo, puede especificar una estructura OVERLAPPED que contiene un evento y puede esperar a que se señale ese evento para indicar que la E / S superpuesta ha finalizado. Esto, supongo, es su enfoque WaitForMultipleObjects () y, como se mencionó anteriormente, no se ajusta bien, ya que está limitado a la cantidad de manejadores que puede pasar a WaitForMultipleObjects ().

Alternativamente, puede pasar una rutina de finalización que se llama cuando se produce la finalización. Esto se conoce como ''E / S con alerta'' y requiere que el subproceso que emitió la llamada WSARecv () esté en un estado de ''alerta'' para que se llame la rutina de finalización. Los subprocesos pueden ponerse en estado de alerta de varias maneras (llamando a SleepEx () o las diversas versiones EX de las funciones de espera, etc.). El libro de Richter que tengo abierto frente a mí dice: "He trabajado bastante con E / S de alerta bastante, y seré el primero en decirle que la E / S de alerta es horrible y debe evitarse". Suficiente dicho IMHO.

Hay una tercera forma: antes de emitir la llamada, debe asociar el identificador con el que desea realizar la E / S superpuesta en un puerto de finalización. A continuación, crea un grupo de subprocesos que dan servicio a este puerto de finalización llamando a GetQueuedCompletionStatus () y formando un bucle. Usted emite su WSARecv () con una estructura OVERLAPPED SIN un evento y cuando la E / S completa la terminación, aparece GetQueuedCompletionStatus () en uno de los subprocesos de la agrupación de E / S y puede manejarse allí.

Como se mencionó anteriormente, Vista / Server 2008 limpió un poco el funcionamiento de los IOCP y eliminó el problema por el cual tenía que asegurarse de que el subproceso que emitió la solicitud superpuesta continuara ejecutándose hasta que la solicitud se completara. Enlace a una referencia que se puede encontrar here . Pero este problema es fácil de solucionar de todos modos; simplemente coloca la WSARecv en uno de los subprocesos de su grupo de E / S utilizando el mismo IOCP que utiliza para las terminaciones ...

De todos modos, IMHO utilizando IOCP es la mejor manera de hacer E / S superpuestas. Sí, hacer que tu cabeza se centre en la naturaleza superpuesta / asíncrona de las llamadas puede tomar un poco de tiempo al principio, pero vale la pena porque el sistema se adapta muy bien y ofrece un método simple de "disparar y olvidar" para tratar las operaciones superpuestas.

Si necesita algo de código de ejemplo para comenzar, tengo varios artículos sobre cómo escribir sistemas de puertos de finalización de E / S y un montón de código gratuito que proporciona un marco del mundo real para servidores de alto rendimiento; ver here

Como un aparte; En mi humilde opinión, realmente debería leer " Windows Via C / C ++ (PRO-Developer) " por Jeffrey Richter y Christophe Nasarre, ya que todo lo que necesita saber sobre la E / S superpuesta y la mayoría de las otras técnicas avanzadas de la plataforma de Windows y las API.


WaitForMultipleObjects está limitado a 64 manejadores; en una aplicación altamente concurrente esto podría convertirse en una limitación.

Los puertos de finalización encajan mejor con un modelo de tener un conjunto de subprocesos que son capaces de manejar cualquier evento, y usted puede poner en cola sus propios eventos (no basados ​​en IO) en el puerto, mientras que con las esperas, tendrá que codificar sus propios eventos. mecanismo.

Sin embargo, los puertos de finalización y el modelo de programación basado en eventos son un concepto más difícil contra el que trabajar.

No esperaría ninguna diferencia significativa en el rendimiento, pero al final solo puede realizar sus propias mediciones para reflejar su uso. Tenga en cuenta que Vista / Server2008 realizó un cambio con los puertos de finalización, ya que ahora el subproceso original no es necesario para completar las operaciones de IO. Esto puede marcar una gran diferencia (consulte este article de Mark Russinovich).