gpt4 book ai didi

haskell - 如何防止 scotty 为大文本输出占用内存?

转载 作者:行者123 更新时间:2023-12-01 03:40:30 26 4
gpt4 key购买 nike

我有一个 Scotty/WAI 应用程序,其中一个端点发送了一个大的 Text从元素列表构建的输出。这是相关的代码:

  import Data.Text.Lazy as L
import Data.Text.Lazy.Encoding as E

class (Show csv) => ToCSV csv where
toCSV :: csv -> L.Text
toCSV = pack . show

instance (ToCSV c) => ToCSV [c] where
toCSV [] = empty
toCSV (c:cs) = toCSV c <> "\n" <> toCSV cs


get "/api/transactions" $ accept "text/csv" $ do
purp <- selectPurpose
txs <- allEntries <$> inWeb (listTransactions purp)
setHeader "Content-Type" "text/csv"
raw $ E.encodeUtf8 $ toCSV txs

据我了解 Scotty's documentation输出应该延迟构建并通过网络发送,而无需在内存中构建整个文本/字节串。然而,这不是我观察到的行为:当我调用这个端点时,服务器开始占用内存,我推断它正在构建整个字符串,然后一次性发送它。

我错过了什么吗?

编辑1:

我写了一个 doStream应该一个接一个地发送结果 BS 块的函数:
doStream :: Text -> W.StreamingBody   
doStream t build flush = do
let bs = E.encodeUtf8 t
mapM_ (\ chunk -> build (B.fromByteString chunk)) (BS.toChunks bs)
flush

但实际上它仍然在内存中构建整个输出......

编辑2:

实际上,以这种方式流式传输工作正常。但是,服务器进程仍然会占用大量内存,在发送每个块时实际上可能会进行垃圾回收。我将尝试更深入地分析内存使用情况,以了解这种消耗来自何处。

编辑3:

我试图将堆限制为 2GB,但这会使进程崩溃。整个转化过程中保留了一些内存......

最佳答案

看看"stream" Web.Scotty.Trans 中的函数。它的目的是对在刷新到套接字之前生成的数据的大小进行更细粒度的控制。

你用一个 StreamingBody 参数调用它,它实际上是一个类型为 (Builder -> IO ()) -> IO () -> IO () 的函数。

所以你写了一个函数:

doMyStreaming send flush =
...

在其中您分块发送和刷新数据,然后使用 doMyStreaming 作为参数调用流函数,而不是调用“raw”。

关于haskell - 如何防止 scotty 为大文本输出占用内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31199923/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com