Ich habe vor einer Weile mit Haskell angefangen und jetzt konzentriere ich mich auf das Networking. Ich folgte setzen einige Tutorials und Quellpunkte zusammen einen sehr einfachen Echo-Server:Haskell - Langsam Steckverbindung bei Gewinde
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)
Jetzt habe ich den Code mit dem ab-Tool zum Benchmark der Server getestet. Der Code wird mit -O2 und-Threaded kompiliert und das Programm wird mit + RTS -N gestartet, um mehrere OS-Threads zu verwenden.
Der Code erstellt einen neuen Lightweight-Thread pro Client und soweit ich mich erinnere, sind diese Threads ziemlich billig, weil sie von einer Reihe von echten OS-Threads geplant werden.
Nachdem das Werkzeug ausgeführt wird, sind die Ergebnisse:
ab -n 10000 -c 1000 http://localhost:8080/
~ 500-1600 req/sec Ja, es manchmal zwischen 500 und 1600 nicht verändert!
Zuerst dachte ich gut, nicht schlecht. Dann habe ich das Programm ohne "+ RTS -N" ausgeführt und die Ergebnisse sind fast alle mal ~ 20000 req/sec.
Offensichtlich tötet das Threading die Leistung ziemlich schlecht, aber warum? Meine Vermutung ist, dass der IO-Manager eine ziemlich schlechte Arbeit leistet, wenn es um viele Verbindungen geht.
BTW: Ich benutze Ubuntu 13.04 und Ghc 7.6, aber ich habe den Code unter Windows 8 getestet, die mir weit schlechtere Ergebnisse gab, aber ich denke, der IO-Manager ist für Linux abgestimmt, was Sinn macht.
Mache ich hier wirklich dumm? Ich weiß, das Beispiel ist ziemlich trivial, aber hier läuft offensichtlich etwas schief.
Grüße, Chris
ist, dass 20 oder 20000 in 20.000 – Satvik
Es ist 20000, sry für das Missverständnis – Kr0e
Wie viele aktuelle Themen hat Ihr Prozessor haben und wie viele echte Threads verwenden Sie (das Argument N) – Satvik