Los servidores Indy usan hilos para gestionar las conexiones de los clientes; cada vez que un nuevo cliente se conecta al servidor se crea un nuevo hilo y este hilo gestiona la conexión, así que si tienes 100 conexiones habrá 100 hilos. Además, Indy usa sockets bloqueantes, lo que significa que cuando lees o escribes, la función no retorna hasta que se completa.
Este modelo tiene algunas ventajas, como que es fácil de programar porque el código se procesa de forma secuencial. Pero como contra, si el número de conexiones aumenta, el rendimiento es cada vez peor debido al cambio de contexto entre hilos. El cambio de contexto es el proceso de almacenar el estado de un hilo para que pueda restaurarse y reanudar la ejecución en un momento posterior. El cambio rápido de contexto entre hilos es caro en términos de utilización de CPU. Si creas 1000 conexiones en un servidor, verás que la cpu está trabajando aunque no haya datos intercambiados; este uso de cpu se debe al cambio de contexto entre hilos.
Alternativas al modelo Indy
En lugar de usar 1 hilo por cada conexión, hay alternativas como IOCP (para Windows) o EPOLL (para Linux) que hacen uso de un pool de hilos para gestionar las conexiones y usan sockets no bloqueantes. Este modelo es mucho más eficiente cuando el número de conexiones concurrentes es alto y escala mucho mejor que el modelo de hilos Indy por defecto.
IOCP (Windows)
I/O completion ports proporciona un modelo de hilos eficiente para procesar múltiples peticiones de E/S asíncronas en un sistema multiprocesador. Cuando un proceso crea un I/O completion port, el sistema crea un objeto de cola asociado para hilos cuyo único propósito es atender estas peticiones. Los procesos que gestionan muchas peticiones de E/S asíncronas concurrentes pueden hacerlo de forma más rápida y eficiente usando I/O completion ports junto con un pool de hilos pre-asignado en lugar de crear hilos en el momento en que reciben una petición de E/S.
El modelo IOCP usa sockets no bloqueantes; en lugar de usar Select hace uso de la función AcceptEx y un pool de hilos para gestionar las conexiones de los clientes.
Para activar IOCP en el servidor Indy de sgcWebSockets, mira el código de abajo
oServer := TsgcWebSocketHTTPServer.Create(nil); oServer.NotifyEvents := neNOSync; oServer.IOHandlerOptions.IOHandlerType := iohIOCP; oServer.Active := True;
Se creará un nuevo servidor WebSocket + HTTP y un pool de hilos gestionará las conexiones; el número de hilos usados dependerá del número de cpu donde se esté ejecutando el servidor.
EPOLL (Linux)
Epoll es una system call del kernel de Linux para un mecanismo escalable de notificación de eventos de E/S, introducido por primera vez en la versión 2.5.44 del kernel de Linux. Su función es monitorizar múltiples file descriptors para ver si es posible E/S en cualquiera de ellos. Está pensado para reemplazar las system calls POSIX más antiguas select y poll, para lograr mejor rendimiento en aplicaciones más exigentes, donde el número de file descriptors observados es grande.
Mira la siguiente tabla comparando el rendimiento para 100.000 operaciones de monitorización:
| Núm. operaciones | poll | select | epoll |
| 10 | 0.61 | 0.73 | 0.41 |
| 100 | 2.9 | 3.0 | 0.42 |
| 1000 | 35 | 35 | 0.53 |
| 10000 | 990 | 930 | 0.66 |
Así que usar epoll realmente es mucho más rápido cuando tienes más de 10 file descriptors aproximadamente que monitorizar.
El modelo EPOLL usa sockets no bloqueantes; en lugar de usar Select hace uso de la función Accept async y un pool de hilos para gestionar las conexiones de los clientes.
Para activar EPOLL en el servidor Indy de sgcWebSockets, mira el código de abajo
oServer := TsgcWebSocketHTTPServer.Create(nil); oServer.NotifyEvents := neNOSync; oServer.IOHandlerOptions.IOHandlerType := iohEPOLL; oServer.Active := True;
