在对前一个问题(haskell-data-hashset-from-unordered-container-performance-for-large-sets)进行一些观察时,我偶然发现了一个奇怪的内存泄漏
module Main where
import System.Environment (getArgs)
import Control.Monad.Trans.Resource (runResourceT)
import Data.Attoparsec.ByteString (sepBy, Parser)
import Data.Attoparsec.ByteString.Char8 (decimal, char)
import Data.Conduit
import qualified Data.Conduit.Attoparsec as CA
import qualified Data.Conduit.Binary as CB
import qualified Data.Conduit.List as CL
main :: IO ()
main = do (args:_) <- getArgs
writeFile "input.txt" $ unlines $ map show [1..4 :: Int]
case args of "list" -> m1
"fail" -> m2
"listlist" -> m3
"memoryleak" -> m4
--UPDATE
"bs-lines":_ -> m5
"bs":_ -> m6
_ -> putStr $ unlines ["Usage: conduit list"
," fail"
," listlist"
," memoryleak"
--UPDATE
," bs-lines"
," bs"
]
m1,m2,m3,m4 :: IO ()
m1 = do hs <- runResourceT
$ CB.sourceFile "input.txt"
$$ CB.lines
=$= CA.conduitParser (decimal :: Parser Int)
=$= CL.map snd
=$= CL.consume
print hs
m2 = do hs <- runResourceT
$ CB.sourceFile "input.txt"
$$ CA.conduitParser (decimal :: Parser Int)
=$= CL.map snd
=$= CL.consume
print hs
m3 = do hs <- runResourceT
$ CB.sourceFile "input.txt"
$$ CB.lines
=$= CA.conduitParser (decimal `sepBy` (char '\n') :: Parser [Int])
=$= CL.map snd
=$= CL.consume
print hs
m4 = do hs <- runResourceT
$ CB.sourceFile "input.txt"
$$ CA.conduitParser (decimal `sepBy` (char '\n') :: Parser [Int])
=$= CL.map snd
=$= CL.consume
print hs
-- UPDATE
m5 = do inpt <- BS.lines <$> BS.readFile "input.txt"
let Right hs = mapM (parseOnly (decimal :: Parser Int)) inpt
print hs
m6 = do inpt <- BS.readFile "input.txt"
let Right hs = (parseOnly (decimal `sepBy` (char '\n') :: Parser [Int])) inpt
print hs下面是一些输出示例:
$ > stack exec -- example list
[1234]
$ > stack exec -- example listlist
[[1234]]
$ > stack exec -- conduit fail
conduit: ParseError {errorContexts = [], errorMessage = "Failed reading: takeWhile1", errorPosition = 1:2}
$ > stack exec -- example memoryleak
(Ctrl+C)
-- UPDATE
$ > stack exec -- example bs-lines
[1,2,3,4]
$ > stack exec -- example bs
[1,2,3,4]现在我要问的问题是:
m1 不生产 [1,2,3,4]**?**?m2 失败?m4 的行为与所有其他版本完全不同,并产生空间泄漏?发布于 2016-03-28 11:38:37
为什么m2失败了?
作为字符流的输入文件是:
1\n2\n3\n4\n由于decimal解析器不需要换行符,所以在使用第一个数字之后,剩下的流是:
\n2\n3\n4\n由于输入流尚未耗尽,conduitParser将再次在流上运行解析器,这一次它甚至无法使用第一个字符,因此失败。
为什么m4的行为与所有其他版本完全不同,并产生空间泄漏?
decimal `sepBy` (char '\n')只使用两个整数之间的\n,在成功解析四个数字之后,输入流中只有一个字符:
\ndecimal `sepBy` (char '\n')不能使用它,更糟糕的是它不会失败:sepBy可以使用任何东西并返回空列表。因此,它不会无限地解析任何东西,也不会终止。
为什么m1不产生1,2,3,4?
我也想知道!我想这与引信有关,也许你应该联系管道包的作者,他刚刚评论了你的问题。
发布于 2016-03-29 06:26:27
要回答有关m1的问题:当您使用CB.lines时,您将转换如下所示的输入:
["1\n2\n3\n4\n"]转入:
["1", "2", "3", "4"]然后,attoparsec解析"1",等待更多的输入,看到"2",等等。
https://stackoverflow.com/questions/36254752
复制相似问题