Os servidores Indy usam threads para gerenciar as conexões dos clientes. Toda vez que um novo cliente se conecta ao servidor, uma nova thread é criada para gerenciar essa conexão. Portanto, se você tiver 100 conexões, haverá 100 threads. Além disso, o Indy usa sockets bloqueantes, o que significa que ao ler ou escrever, a função não retorna até que a operação seja concluída.
Esse modelo tem algumas vantagens, como ser fácil de programar, pois o código é processado sequencialmente. Porém, como desvantagem, se o número de conexões aumentar, o desempenho piora progressivamente devido à troca de contexto de threads. A troca de contexto é o processo de armazenar o estado de uma thread para que ela possa ser restaurada e retomar a execução posteriormente. A troca rápida de contexto entre threads é custosa em termos de utilização de CPU. Se você criar 1000 conexões em um servidor, verá que a CPU está trabalhando mesmo sem nenhuma troca de dados — esse uso de CPU se deve à troca de contexto de threads.
Alternativas ao Modelo Indy
Em vez de usar 1 thread por conexão, existem alternativas como IOCP (para Windows) ou EPOLL (para Linux), que utilizam um pool de threads para gerenciar as conexões e usam sockets não bloqueantes. Esse modelo é muito mais eficiente quando o número de conexões simultâneas é alto e escala muito melhor do que o modelo padrão de threads do Indy.
IOCP (Windows)
As portas de conclusão de E/S fornecem um modelo de threading eficiente para processar múltiplas requisições de E/S assíncronas em um sistema multiprocessador. Quando um processo cria uma porta de conclusão de E/S, o sistema cria um objeto de fila associado para threads cujo único propósito é atender essas requisições. Processos que lidam com muitas requisições de E/S assíncronas simultâneas podem fazê-lo de forma mais rápida e eficiente usando portas de conclusão de E/S em conjunto com um pool de threads pré-alocado, em vez de criar threads no momento em que recebem uma requisição de E/S.
O modelo IOCP usa sockets não bloqueantes; em vez de usar Select, utiliza a função AcceptEx e um pool de threads para gerenciar as conexões dos clientes.
Para habilitar o IOCP no servidor Indy do sgcWebSockets, veja o código abaixo:
oServer := TsgcWebSocketHTTPServer.Create(nil); oServer.NotifyEvents := neNOSync; oServer.IOHandlerOptions.IOHandlerType := iohIOCP; oServer.Active := True;
Um novo servidor WebSocket + HTTP será criado e um pool de threads gerenciará as conexões. O número de threads utilizadas dependerá do número de CPUs do servidor.
EPOLL (Linux)
O Epoll é uma chamada de sistema do kernel Linux para um mecanismo escalável de notificação de eventos de E/S, introduzido pela primeira vez na versão 2.5.44 do kernel Linux. Sua função é monitorar múltiplos descritores de arquivo para verificar se é possível realizar E/S em algum deles. Ele foi criado para substituir as chamadas de sistema POSIX select e poll mais antigas, a fim de obter melhor desempenho em aplicações mais exigentes, onde o número de descritores de arquivo monitorados é grande.
Confira a tabela a seguir comparando o desempenho para 100.000 operações de monitoramento:
| Núm. de Operações | 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 |
Portanto, usar o epoll é muito mais rápido quando você tem mais de 10 descritores de arquivo para monitorar.
O modelo EPOLL usa sockets não bloqueantes; em vez de usar Select, utiliza a função Accept assíncrona e um pool de threads para gerenciar as conexões dos clientes.
Para habilitar o EPOLL no servidor Indy do sgcWebSockets, veja o código abaixo:
oServer := TsgcWebSocketHTTPServer.Create(nil); oServer.NotifyEvents := neNOSync; oServer.IOHandlerOptions.IOHandlerType := iohEPOLL; oServer.Active := True;
