sockets - 从 Socket 句柄构建的惰性 ByteString 无法被延迟使用和 GC

标签 sockets memory haskell lazy-evaluation bytestring

我正在编写一个网络文件传输应用程序。使用 Lazy ByteString 作为中间体

import qualified Data.ByteString.Lazy as BSL

当从本地文件构造 BSL 时,然后将 BSL 放入 Socket 的句柄:

BSL.readFile filename >>= BSL.hPut remoteH  -- OK

这很好用。内存使用量是恒定的。但对于从Socket接收数据,然后写入本地文件:

BSL.hGet remoteH size >>= BSL.hPut fileH bs  -- starts swapping in 1 second

我可以看到内存使用量持续上升,BSL 占用了 size 字节的内存。 更糟糕的是,对于超过我的物理内存大小的大大小,操作系统立即开始交换。

我必须递归地接收字节字符串段。没关系。

为什么BSL会有这样的行为?

最佳答案

hGet 是严格的——它立即要求您请求的字节数。这样做是为了促进数据包级别的数据读取。

但是,hGetContentsN 是惰性的,而 readFile 是根据 hGetContentsN 实现的。

考虑两种实现:

hGetContentsN :: Int -> Handle -> IO ByteString
hGetContentsN k h = lazyRead -- TODO close on exceptions
  where
    lazyRead = unsafeInterleaveIO loop

    loop = do
        c <- S.hGetSome h k -- only blocks if there is no data available
        if S.null c
          then do hClose h >> return Empty
          else do cs <- lazyRead
                  return (Chunk c cs)

hGet :: Handle -> Int -> IO ByteString
hGet = hGetN defaultChunkSize

hGetN :: Int -> Handle -> Int -> IO ByteString
hGetN k h n | n > 0 = readChunks n
  where
    STRICT1(readChunks)
    readChunks i = do
        c <- S.hGet h (min k i)
        case S.length c of
            0 -> return Empty
            m -> do cs <- readChunks (i - m)
                    return (Chunk c cs)

关键的魔力在于 hGetContentsN 中的惰性。

关于sockets - 从 Socket 句柄构建的惰性 ByteString 无法被延迟使用和 GC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10649636/

相关文章:

iOS swift单例初始化方法

c - 函数接收 char * 就好像它是空的

ruby-on-rails - 如何在 Rails 应用程序中获取内存使用情况?

c# - 具有 C# 结构的生产者/消费者?

haskell - 如何声明两种类型的组合是一个 monad

python - 如何在websocket python中发送 'Headers'

c - 预取对齐内存

具有多个参数和类型问题的 Haskell 映射

haskell - 稍微复杂 [String] -> [UTCTime]

PHP Web 套接字 - 无法绑定(bind)到主机