什么时候调用 runResourceT on streaming-bytestring?
When to call runResourceT on streaming-bytestring?
我是 Haskell 初学者,仍在学习 monad 转换器。
我正在尝试使用 streaming-bytestring library to read a binary file, process chunks of bytes, and print the result as each chunk is processed. I believe this is the popular streaming
library that provides an alternative to lazy bytestrings. It appears the authors copy-pasted the lazy bytestring 文档并添加了一些任意示例。
这些示例提到了 runResourceT
,但没有讨论它是什么或如何使用它。似乎应该在执行操作的任何流字节串函数上使用 runResourceT
。这很好,但是如果我正在读取处理块并打印它们的无限流怎么办?我是否应该在每次处理块时都调用 runResourceT?
我的代码是这样的:
import qualified Data.ByteString.Streaming as BSS
import System.TimeIt
main = timeIt $ processByteChunks $ BSS.drop 100 $ BSS.readFile "filename"
而且我不确定如何将 processByteChunks
组织为遍历二进制文件的递归函数。
如果我只调用 runResourceT
一次,它会在打印前读取无限文件,对吧?这似乎很糟糕。
main = timeIt $ runResourceT $ processByteChunks $ BSS.drop 100 $ BSS.readFile "filename"
ResourceT
monad 会在您用完资源后及时清理它们。在这种情况下,它将确保在使用流时关闭 BSS.readFile
打开的文件句柄。 (除非流真的是无限的,在这种情况下我猜它不会。)
在您的应用程序中,您只想调用它一次,因为您不想在读取所有块之前关闭文件。别担心——它与输出时间或类似的东西无关。
这是一个递归 processByteChunks
应该可以工作的示例。它将延迟读取并在块被延迟读取时生成输出:
import Control.Monad.IO.Class
import Control.Monad.Trans.Resource
import qualified Data.ByteString.Streaming as BSS
import qualified Data.ByteString as BS
import System.TimeIt
main :: IO ()
main = timeIt $ runResourceT $
processByteChunks $ BSS.drop 100 $ BSS.readFile "filename"
processByteChunks :: MonadIO m => BSS.ByteString m () -> m ()
processByteChunks = go 0 0
where go len nulls stream = do
m <- BSS.unconsChunk stream
case m of
Just (bs, stream') -> do
let len' = len + BS.length bs
nulls' = nulls + BS.length (BS.filter (==0) bs)
liftIO $ print $ "cumulative length=" ++ show len'
++ ", nulls=" ++ show nulls'
go len' nulls' stream'
Nothing -> return ()
我是 Haskell 初学者,仍在学习 monad 转换器。
我正在尝试使用 streaming-bytestring library to read a binary file, process chunks of bytes, and print the result as each chunk is processed. I believe this is the popular streaming
library that provides an alternative to lazy bytestrings. It appears the authors copy-pasted the lazy bytestring 文档并添加了一些任意示例。
这些示例提到了 runResourceT
,但没有讨论它是什么或如何使用它。似乎应该在执行操作的任何流字节串函数上使用 runResourceT
。这很好,但是如果我正在读取处理块并打印它们的无限流怎么办?我是否应该在每次处理块时都调用 runResourceT?
我的代码是这样的:
import qualified Data.ByteString.Streaming as BSS
import System.TimeIt
main = timeIt $ processByteChunks $ BSS.drop 100 $ BSS.readFile "filename"
而且我不确定如何将 processByteChunks
组织为遍历二进制文件的递归函数。
如果我只调用 runResourceT
一次,它会在打印前读取无限文件,对吧?这似乎很糟糕。
main = timeIt $ runResourceT $ processByteChunks $ BSS.drop 100 $ BSS.readFile "filename"
ResourceT
monad 会在您用完资源后及时清理它们。在这种情况下,它将确保在使用流时关闭 BSS.readFile
打开的文件句柄。 (除非流真的是无限的,在这种情况下我猜它不会。)
在您的应用程序中,您只想调用它一次,因为您不想在读取所有块之前关闭文件。别担心——它与输出时间或类似的东西无关。
这是一个递归 processByteChunks
应该可以工作的示例。它将延迟读取并在块被延迟读取时生成输出:
import Control.Monad.IO.Class
import Control.Monad.Trans.Resource
import qualified Data.ByteString.Streaming as BSS
import qualified Data.ByteString as BS
import System.TimeIt
main :: IO ()
main = timeIt $ runResourceT $
processByteChunks $ BSS.drop 100 $ BSS.readFile "filename"
processByteChunks :: MonadIO m => BSS.ByteString m () -> m ()
processByteChunks = go 0 0
where go len nulls stream = do
m <- BSS.unconsChunk stream
case m of
Just (bs, stream') -> do
let len' = len + BS.length bs
nulls' = nulls + BS.length (BS.filter (==0) bs)
liftIO $ print $ "cumulative length=" ++ show len'
++ ", nulls=" ++ show nulls'
go len' nulls' stream'
Nothing -> return ()