【发布时间】:2013-06-05 20:42:37
【问题描述】:
我不久前开始使用 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 请求/秒
是的,它有时会在 500 到 1600 之间变化!
一开始我觉得不错,还不错。然后我在没有“+RTS -N”的情况下运行程序,结果几乎是每个 时间 ~20000 请求/秒。
显然线程会严重影响性能,但为什么呢? 我的猜测是,IO 管理器在处理大量连接时做得很糟糕。
顺便说一句:我使用的是 Ubuntu 13.04 和 ghc 7.6,但我在 Windows 8 下测试了代码,结果差很多,但我认为 IO 管理器针对 linux 进行了调整,这是有道理的。
我在这里做的事情真的很愚蠢吗?我知道,这个例子很简单,但这里显然出了点问题。
问候, 克里斯
【问题讨论】:
-
是 20.000 中的 20 还是 20000
-
20000,误会见谅
-
您的处理器有多少实际线程以及您使用了多少实际线程(-N 的参数)
-
这是一个具有 4 个真正核心的 i5。所以 -N 等于 -N4
标签: multithreading performance sockets networking haskell