Multiplexación de E / S (select / poll / epol) y el modelo de E / S "asincrónico" implementado mediante el uso de goroutine y multiplexación de E / S en golangIO

Reimpreso de: https://zhuanlan.zhihu.com/p/344581947

Solo para copias de seguridad personales, consulte el texto original para navegar

 

Tabla de contenido

modelo io

Bloqueo de E / S

E / S sin bloqueo

Multiplexación IO (incluyendo: select / poll / epoll)

La diferencia entre select / poll / epoll

introducción epoll

E / S asíncrona

Ideas de implementación de E / S asíncronas de Golang


 

El uso de Golang puede crear fácilmente una corrutina para que cada conexión TCP sirva sin preocuparse por problemas de rendimiento. Esto se debe a que Go usa internamente una gorutina combinada con multiplexación de E / S para implementar un modelo de E / S "asincrónico", lo que hace que los desarrolladores sean innecesarios Se presta demasiada atención a la capa inferior, y solo la lógica empresarial de la capa superior debe escribirse según sea necesario. ¿Cómo se logra esta IO asincrónica? A continuación analizaré el sistema Linux.

En el sistema Unix / Linux, todo es un archivo. Cada conexión TCP corresponde a un identificador de socket. Este identificador también se puede considerar como un archivo. Enviar y recibir datos en el socket equivale a leer y escribir un archivo, por lo que un identificador de socket , Usualmente también se usa para representar el descriptor de archivo fd. Puede ingresar / proc / PID / fd / para ver el fd ocupado por el proceso.

El núcleo del sistema asigna un búfer de lectura (recepción) y un búfer de escritura (envío) para cada controlador de socket. Enviar datos es escribir datos en el búfer de escritura correspondiente a este fd, y recibir datos es leer datos en el búfer de lectura. Cuando el programa llama a escribir o enviar, no significa que los datos se envíen, solo copia los datos al búfer de escritura.Cuando sea el momento adecuado (acumulado a una cierta cantidad), los datos se enviarán al destino.

El tiempo de ejecución de Golang todavía necesita verificar con frecuencia si fd está listo. Estrictamente hablando, no es realmente asíncrono, sino una reutilización de E / S sin bloqueo.

modelo io

Bloqueo de E / S

Cuando el programa quiere leer datos en el búfer, el búfer no necesariamente tiene datos, lo que provocará una llamada al sistema y solo puede esperar a que se lean los datos. Cuando no hay datos para leer, bloqueará el proceso. Esto está bloqueando la E / S. Cuando necesite proporcionar servicios para varios clientes, puede utilizar el enfoque de subprocesos. Cada identificador de socket utiliza un subproceso para servir, por lo que se bloquea un determinado subproceso. Aunque esto puede resolver la congestión del proceso, todavía hay una cantidad considerable de recursos de CPU desperdiciados esperando por datos. Al mismo tiempo, usar subprocesos para servir fd es un desperdicio de recursos, porque si hay más fd para ser procesados, es otra sobrecarga de recursos.

 

 

E / S sin bloqueo

Correspondiente a él es IO sin bloqueo Cuando el programa quiere leer datos, si el búfer no existe, volverá directamente al programa de usuario, pero el programa de usuario necesita verificar con frecuencia hasta que los datos estén listos. Esto también provocará un consumo de CPU vacío.

 

 

Multiplexación IO (incluyendo: select / poll / epoll)

Contiene: select / poll / epoll

Y la multiplexación de IO es diferente, usará un hilo para administrar múltiples fd, puede agregar múltiples fd a la función de multiplexación de IO, cada vez que se llame a la función, pase el fd para verificar, si está listo FD, regrese directamente ready fd, y luego inicie el procesamiento del hilo o procese secuencialmente el ready fd. Esto logra que un subproceso administre múltiples tareas fd, lo cual es relativamente eficiente. Las funciones comunes de multiplexación de E / S incluyen select, poll y epoll. La mayor desventaja de select y poll es que cada llamada necesita pasar todas las colecciones fd para ser monitoreadas, y el kernel atraviesa esta colección fd entrante. Cuando la cantidad de simultaneidad es grande, los datos se copian entre el modo de usuario y el kernel mode y el kernel Polling fd desperdiciará una ola de recursos del sistema (no para expandir select y poll aquí).

 

La diferencia entre select / poll / epoll

La multiplexación de E / S es un mecanismo a través del cual un proceso puede monitorear múltiples descriptores de archivos. Una vez que un descriptor está listo (listo para leer o escribir), puede notificar al programa para que realice las operaciones de lectura y escritura correspondientes. Sin embargo, la naturaleza de select, poll y epoll todavía se encuentra en la categoría de E / S síncrona (la multiplexación de E / S en sí misma es IO síncrona), porque todos necesitan el hilo para leer y escribir después de que el evento de lectura y escritura esté listo. , y el proceso de lectura y escritura está bloqueado. de. La realización de E / S asíncronas es que el sistema será responsable de copiar los datos del espacio del kernel al espacio del usuario, sin que el hilo en sí mismo bloquee la lectura y escritura, el kernel está listo para completarse.

(1) La implementación de select y poll necesita sondear continuamente todas las colecciones fd por sí misma hasta que el dispositivo esté listo, durante el cual puede alternar entre dormir y despertar varias veces. De hecho, epoll también necesita llamar a epoll_wait para sondear continuamente la lista lista. Durante este período, puede dormir y despertarse alternativamente. Sin embargo, llama a la función de devolución de llamada cuando el dispositivo está listo, coloca el fd listo en la lista lista. y se despierta para dormir en el proceso epoll_wait. Aunque tienen que dormir y alternar, seleccionar y sondear necesitan recorrer todo el conjunto fd cuando están "despiertos", y cuando epoll está "despierto", solo necesita juzgar si la lista lista está vacía, lo que ahorra mucho Tiempo de CPU. Esta es la mejora de rendimiento que aporta el mecanismo de devolución de llamada.

(2) Seleccionar, sondear cada llamada para copiar la colección fd del modo de usuario al modo kernel y colgar la corriente en la cola de espera del dispositivo una vez, mientras que epoll solo necesita copiar una vez y colgar la corriente en la cola de espera. Colgar sólo una vez ( al comienzo de epoll_wait, tenga en cuenta que la cola de espera aquí no es una cola de espera de dispositivo, sino una cola de espera definida dentro de epoll). Esto también puede ahorrarle muchos gastos generales.

introducción epoll

A continuación, introduzca la llamada al sistema epoll

En comparación con select y poll, epoll es más flexible y eficiente y ofrece a los usuarios tres funciones de llamada al sistema. La capa inferior de Golang es el IO "asincrónico" que se completa al combinar estas tres llamadas al sistema con goroutine.

//用于创建并返回一个epfd句柄,后续关于fd的添加删除等操作都依据这个句柄。
int epoll_create(int size);
//用于向epfd添加,删除,修改要监听的fd。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);
//传入创建返回的epfd句柄,以及超时时间,返回就绪的fd句柄。
int epoll_wait(int epfd, struct epoll_event* events, int maxevents, int timeout);
  • Llamar a epoll_create creará un objeto eventpoll en el kernel, que mantendrá una colección epitem, que puede entenderse simplemente como una colección fd.
  • Llamar a la función epoll_ctl se usa para encapsular fd en epitem para unirse al objeto eventpoll, y agregar una función de devolución de llamada a este epitem para registrarlo con el kernel, que se activará cuando cambie el estado de este fd, de modo que se agregue el epitem a la lista lista eventpoll rdlist.
  • Cuando llegan los datos correspondientes, se activa el programa de respuesta a la interrupción, los datos se copian en el búfer de socket de fd, el estado del búfer de fd cambia y la función de devolución de llamada agrega el epitem correspondiente a fd a la cola lista de rdlist.
  • Cuando se llama a epoll_wait, no hay necesidad de atravesar, pero se devuelve la cola lista rdlist.Si la cola rdlist está vacía, la espera se bloquea o llega el tiempo de espera.

El principio de funcionamiento general se muestra en la figura.

 

 

E / S asíncrona

Cuando el programa de usuario quiere leer datos de fd, la llamada al sistema informa directamente al kernel y vuelve a manejar otras cosas.Después de que el kernel prepara los datos, notifica al programa de usuario y el programa de usuario procesa el evento en el fd.

 

 

Ideas de implementación de E / S asíncronas de Golang

Todos sabemos que la ocupación de recursos de la corrutina es muy pequeña, y la corrutina también tiene una variedad de estados como bloqueado, listo, en ejecución, etc. Puede usar una corrutina para servir un fd sin preocuparse por problemas de recursos. El evento de monitoreo de fd se entrega al runtime para que lo administre, para que realice la programación de la co-rutina y los eventos que dependen de fd. Cuando se requiera que la corrutina lea datos fd pero no haya datos, estacione la corrutina (cambie a Gwaiting) y programe otras corrutinas para que se ejecuten.

Al ejecutar la programación de la corrutina, verifique si el fd está listo. Si está listo, el programador informa al fd de la corrutina que el parque en el que vive se puede procesar (cambiar a Grunnable y agregarlo a la cola de ejecución), y la corrutina procesa el fd datos, de modo que ambos Redujeron el consumo de vacío de la CPU, pero también se dieron cuenta de la notificación del mensaje, y realizaron un modelo IO asíncrono desde el nivel de usuario.

 

 

La idea general de Golang netpoll es esta

Supongo que te gusta

Origin blog.csdn.net/chushoufengli/article/details/115231156
Recomendado
Clasificación