Zacząłem od Haskella jakiś czas temu, a teraz koncentruję się na tworzeniu sieci. I przestrzegać pewnych tutoriale i próbek źródłowych ułożyła bardzo prosty serwer echo:Haskell - Wolne połączenie z gniazdem po nagwintowaniu
main = withSocketsDo $ do
forkIO $ acceptor 8080
print "Server running ... " >> getLine >>= print
tcpSock :: IO Socket
tcpSock = socket AF_INET Stream 0
acceptor :: PortNumber -> IO()
acceptor port = do
-- Setup server socket
sock <- tcpSock
setSocketOption sock ReuseAddr 1
bindSocket sock (SockAddrInet port iNADDR_ANY)
listen sock 50
-- Start with zero index
loop sock 0
where
loop sock sockId = do
-- Accept socket
(nextSock, addr) <- accept sock
-- Setup the socket for performance
(_, handle) <- setupClient nextSock
-- Run client in own thread
forkIO $ do
-- Get a stream of bytes
stream <- BS.hGetContents handle
-- Echo the first received char
BS.hPut handle $ BS.take 1 stream
-- Kill the socket
SIO.hClose handle
-- Accept next client
loop sock (sockId + 1)
setupClient :: Socket -> IO (Socket, SIO.Handle)
setupClient sock = do
-- Disable nagle
setSocketOption sock NoDelay 1
-- Disable buffering
hdl <- socketToHandle sock SIO.ReadWriteMode
SIO.hSetBuffering hdl SIO.NoBuffering
return (sock, hdl)
Teraz Przetestowałem kod z AB-narzędziem do benchmarku serwerze. Kod jest kompilowany przy użyciu -O2 i -threaded, a program jest uruchamiany za pomocą + RTS -N, aby używać wielu wątków systemu operacyjnego.
Kod tworzy nowy lekki wątek na klienta i o ile pamiętam, te wątki są dość tanie, ponieważ są zaplanowane przez kilka rzeczywistych wątków systemu operacyjnego.
Po uruchomieniu narzędzia, wyniki są następujące:
ab -n 10000 -c 1000 http://localhost:8080/
~ 500 - 1600 req/s Tak, to nie zmienia czasami między 500 a 1600!
Na początku myślałem dobrze, nieźle. Następnie uruchomiłem program bez "+ RTS -N" i wyniki są prawie co czas ~ 20000 req/sec.
Oczywiście wątki zabijają wydajność bardzo źle, ale dlaczego? Domyślam się, że menedżer IO wykonuje niezłą robotę, kiedy ma do czynienia z wieloma połączeniami.
BTW: Używam Ubuntu 13.04 i ghc 7.6, ale testowałem kod pod Windows 8, co dało mi znacznie gorsze wyniki, ale myślę, że menedżer IO jest dostrojony do systemu Linux, co ma sens.
Czy robię coś naprawdę głupiego tutaj? Wiem, że przykład jest dość banalny, ale tutaj oczywiście coś idzie nie tak.
Pozdrowienia, Chris
to 20 lub 20000 w 20 000 – Satvik
To 20000, proszę o nieporozumienie – Kr0e
Ile wątków ma twój procesor i ile wątków używasz (argument -N) – Satvik