Indy-servers gebruiken threads om de clientverbindingen af te handelen. Telkens wanneer een nieuwe client verbinding maakt met de server, wordt er een nieuwe thread aangemaakt die de verbinding afhandelt, dus bij 100 verbindingen heb je 100 threads. Bovendien gebruikt Indy blocking sockets, wat betekent dat de functie tijdens lezen of schrijven niet terugkeert totdat de bewerking voltooid is.
Dit model heeft een aantal voordelen, zoals dat het gemakkelijk te programmeren is omdat de code sequentieel wordt verwerkt. Een nadeel is echter dat de prestaties bij een toenemend aantal verbindingen steeds verder achteruitgaan door de thread context switch. Context switching is het proces waarbij de toestand van een thread wordt opgeslagen zodat de uitvoering later kan worden hervat. Snel wisselen van context tussen threads is duur qua CPU-gebruik. Als je 1000 verbindingen op een server maakt, zie je dat de CPU bezig is hoewel er geen data wordt uitgewisseld; dit CPU-gebruik komt door de thread context switch.
Alternatieven voor het Indy-model
In plaats van 1 thread per verbinding zijn er alternatieven zoals IOCP (voor Windows) of EPOLL (voor Linux) die een threadpool gebruiken om de verbindingen af te handelen en non-blocking sockets gebruiken. Dit model is veel efficiënter bij een hoog aantal gelijktijdige verbindingen en schaalt veel beter dan het standaard Indy-threadmodel.
IOCP (Windows)
I/O-completion-ports bieden een efficiënt threadmodel voor het verwerken van meerdere asynchrone I/O-aanvragen op een systeem met meerdere processoren. Wanneer een proces een I/O-completion-port aanmaakt, maakt het systeem een bijbehorend queue-object aan voor threads die uitsluitend dienen om deze aanvragen af te handelen. Processen die veel gelijktijdige asynchrone I/O-aanvragen verwerken, kunnen dit sneller en efficiënter doen door I/O-completion-ports te combineren met een vooraf gealloceerde threadpool, in plaats van threads aan te maken op het moment dat ze een I/O-aanvraag ontvangen.
Het IOCP-model gebruikt non-blocking sockets; in plaats van Select wordt de AcceptEx-functie gebruikt, samen met een threadpool om de clientverbindingen af te handelen.
Om IOCP op de Indy-server van sgcWebSockets in te schakelen, bekijk je de onderstaande code
oServer := TsgcWebSocketHTTPServer.Create(nil); oServer.NotifyEvents := neNOSync; oServer.IOHandlerOptions.IOHandlerType := iohIOCP; oServer.Active := True;
Er wordt een nieuwe WebSocket + HTTP-server gemaakt en een threadpool handelt de verbindingen af; het aantal gebruikte threads is afhankelijk van het aantal CPU's waarop de server draait.
EPOLL (Linux)
Epoll is een Linux-kernel-systeemaanroep voor een schaalbaar mechanisme voor I/O-eventmeldingen, voor het eerst geïntroduceerd in versie 2.5.44 van de Linux-kernel. Het doel is om meerdere file descriptors te monitoren om te zien of er op een ervan I/O mogelijk is. Het is bedoeld om de oudere POSIX-systeemaanroepen select en poll te vervangen om betere prestaties te bereiken in veeleisende toepassingen waarin het aantal gemonitorde file descriptors groot is.
Bekijk de onderstaande tabel met een prestatievergelijking voor 100.000 monitoringbewerkingen:
| Aant. bewerkingen | 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 |
Epoll gebruiken is dus echt een stuk sneller zodra je meer dan ongeveer 10 file descriptors moet monitoren.
Het EPOLL-model gebruikt non-blocking sockets; in plaats van Select wordt de Accept async functie gebruikt, samen met een threadpool om de clientverbindingen af te handelen.
Om EPOLL op de Indy-server van sgcWebSockets in te schakelen, bekijk je de onderstaande code
oServer := TsgcWebSocketHTTPServer.Create(nil); oServer.NotifyEvents := neNOSync; oServer.IOHandlerOptions.IOHandlerType := iohEPOLL; oServer.Active := True;
