forkIO似乎阻止了haskell websocket服务器

时间:2016-03-16 19:38:31

标签: multithreading haskell threadscope

我正在使用Wai运行一个haskell websocket服务器:

application :: MVar ServerState -> Wai.Application
application state = WaiWS.websocketsOr WS.defaultConnectionOptions wsApp staticApp
  where
    wsApp :: WS.ServerApp
    wsApp pendingConn = do
      conn <- WS.acceptRequest pendingConn 
      talk conn state

为了允许单个客户端发送异步消息,talk定义如下:

talk :: WS.Connection -> MVar ServerState -> IO ()
talk conn state = forever $ do
  msg <- WS.receiveMessage conn

  putStrLn "received message"

  successLock <- newEmptyMVar 
  tid <- timeoutAsync successLock $ processMessage c state msg

  putStrLn "forked thread"

  modifyMVar_ state $ \curState -> 
    return $ curState & threads %~ (M.insert mid tid) -- thread bookkeeping

  putStrLn "modified state"

  putMVar successLock ()
  putStrLn "unlocked success"

  where
    mid                 = serverMessageId msg
    timeoutAsync lock f = forkIO $ do
      timeout S.process_message_timeout onTimeout (onSuccess lock) f
    onSuccess lock      = do
      -- block until the first modifyMVar_ above finishes.
      takeMVar lock
      modifyMVar_ state $ \curState -> 
        return $ curState & threads %~ (M.delete mid) -- thread cleanup
    onTimeout = ...

事情就是这样:当我用大量CPU消息(来自单个客户端)轰炸这个服务器时,主线程偶尔会挂起“分叉线程”

这是令人惊讶的,因为所有关于消息的工作(理论上)都是在不同的线程中完成的,因此主线程(forever永远不应该阻止

这里发生了什么?

[编辑]

在这种情况下,很难提供最小的可验证示例(工作在processMessage完成,但包含许多移动部件,其中任何一个都可能是问题)。相反,我正在寻找可以调查的事情的高级指针。

以下是来自示例运行的数据(向服务器发送一个昂贵的请求,然后是一堆较小的较便宜的请求):

此外,该应用程序具有以下属性,我认为这是导致问题的潜在原因:

  • GC'd与实时数据的比率很高; processMessage基本上构建了一个巨大的列表aeson'd并发回给用户,但没有保持状态

  • 在一次请求中发出了许多外国电话(由于ZMQ,iirc发出不安全的外国电话)

  • ThreadScope告诉我发生了很多堆溢出,导致GC请求

0 个答案:

没有答案