我尝试使用Haskell Snap框架提供大量HTTP响应,但内存使用量与响应大小成比例增长。这里有几个使用大型惰性ByteString的简化测试用例:
import Snap.Core (Snap, writeLBS, readRequestBody)
import Snap.Http.Server (quickHttpServe)
import Control.Monad.IO.Class (MonadIO(liftIO))
import qualified Data.ByteString.Lazy.Char8 as LBS (ByteString, length, replicate)
main :: IO ()
main = quickHttpServe $ site test1 where
test1, test2 :: LBS.ByteString -> Snap ()
-- Send ss to client
test1 = writeLBS
-- Print ss to stdout upon receiving request
test2 = liftIO . print
site write = do
body <- readRequestBody 1000
-- Making ss dependant on the request stops GHC from keeping a
-- reference to ss as pointed out by Reid Barton.
let bodyLength = fromIntegral $ LBS.length body
write $ ss bodyLength
ss c = LBS.replicate (1000000000000 * (c + 1)) 'S'
使用分块编码传递响应,因此我认为Snap也应该能够在常量内存中传递响应。有没有办法实现这个目标?值得注意的是,响应立即开始传递。我尝试过使用transformRequestBody,但遇到了同样的问题。
使用&#34; top&#34;测量记忆。在Linux上,观察到稳定增长到15GB驻留,此时它刚刚开始交换。请求完成后,因此内存使用量比ByteString的大小少几个数量级。一旦请求完成,它就坐在15Gb的居民身边。当我向它发出另一个请求时,它仍然稳定在15Gb,并像以前一样完成了请求。虚拟大小保持在居民规模的5%之内。
首先发现2个并发请求导致虚拟和常驻内存下降到大约5Gb,然后增加到大约17Gb,此时机器无法使用,所以我终止了这个过程。
GHC版本7.8.3
Snap版本0.14.0.5