Когда вызывать runResourceT для streaming-bytestring? - PullRequest
0 голосов
/ 12 мая 2019

Я новичок в Haskell и все еще изучаю монадные трансформаторы.

Я пытаюсь использовать библиотеку streaming-bytestring для чтения двоичного файла, обработки кусков байтов и печати результата при обработке каждого кусочка. Я считаю, что это популярная библиотека streaming, которая предоставляет альтернативу ленивым строкам. Похоже, авторы скопировали документацию 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"

1 Ответ

3 голосов
/ 12 мая 2019

Монада ResourceT просто очищает ресурсы своевременно, когда вы закончите с ними.В этом случае он будет гарантировать, что дескриптор файла, открытый 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 ()
...