5

不久前我开始使用 Haskell,现在我专注于网络。我按照一些教程和源示例组装了一个非常简单的回显服务器:

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)

现在,我已经使用 ab-Tool 测试了代码以对服务器进行基准测试。代码使用 -O2 和 -thread 编译,程序使用 +RTS -N 启动以使用多个 OS 线程。

该代码为每个客户端创建了一个新的轻量级线程,据我所知,这些线程非常便宜,因为它们是由一堆真正的操作系统线程调度的。

运行该工具后,结果如下:

ab -n 10000 -c 1000 http://localhost:8080/ ~ 500 - 1600 req/sec 是的,它有时会在 500 到 1600 之间变化!

一开始我觉得不错,还不错。然后我在没有“+RTS -N”的情况下运行程序,结果几乎每次都为 ~20000 req/sec。

显然线程会严重影响性能,但为什么呢?我的猜测是,IO 管理器在处理大量连接时做得很糟糕。

顺便说一句:我使用 Ubuntu 13.04 和 ghc 7.6,但我在 Windows 8 下测试了代码,结果更差,但我认为 IO 管理器针对 linux 进行了调整,这是有道理的。

我在这里做的事情真的很愚蠢吗?我知道,这个例子很简单,但这里显然出了点问题。

问候,克里斯

4

1 回答 1

1

好的,我想我半解决了这个问题,尽管我仍然不确定错误在哪里。

我现在正在使用 Network 包,因此接受例程是基于句柄的。我尝试了这个,因为在几次测试后我注意到内存泄漏。

这样我一次解决了两个问题,因为现在线程没有任何区别。我真的不知道为什么会这样,但是基于句柄的 impl。更简单,显然更快/更安全。

也许这可以帮助其他遇到同样问题的人。

于 2013-06-06T09:16:10.280 回答