2013-06-05 15 views
5

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

+0

to 20 lub 20000 w 20 000 – Satvik

+0

To 20000, proszę o nieporozumienie – Kr0e

+0

Ile wątków ma twój procesor i ile wątków używasz (argument -N) – Satvik

Odpowiedz

1

Okay, myślę, że pół-rozwiązany problem, choć ja wciąż nie jestem pewien, gdzie błąd jest/był.

Używam teraz pakietu Network, więc procedura akceptacji opiera się na obsłudze. Próbowałem tego, ponieważ po kilku testach zauważyłem wyciek pamięci.

W ten sposób rozwiązałem magicznie dwa problemy naraz, ponieważ teraz nic nie robi różnicy. Naprawdę nie wiem, dlaczego tak się dzieje, ale impl-impl impl. jest prostszy i oczywiście szybszy/bezpieczniejszy.

Może to pomaga innym osobom doświadczającym tego samego problemu.

+1

jak wygląda twój kod teraz? – chespinoza

Powiązane problemy