首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >管道:产生内存泄漏

管道:产生内存泄漏
EN

Stack Overflow用户
提问于 2016-03-28 01:45:05
回答 2查看 159关注 0票数 3

在对前一个问题(haskell-data-hashset-from-unordered-container-performance-for-large-sets)进行一些观察时,我偶然发现了一个奇怪的内存泄漏

代码语言:javascript
复制
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

下面是一些输出示例:

代码语言:javascript
复制
$ > 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 的行为与所有其他版本完全不同,并产生空间泄漏?
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-03-28 11:38:37

为什么m2失败了?

作为字符流的输入文件是:

代码语言:javascript
复制
1\n2\n3\n4\n

由于decimal解析器不需要换行符,所以在使用第一个数字之后,剩下的流是:

代码语言:javascript
复制
\n2\n3\n4\n

由于输入流尚未耗尽,conduitParser将再次在流上运行解析器,这一次它甚至无法使用第一个字符,因此失败。

为什么m4的行为与所有其他版本完全不同,并产生空间泄漏?

decimal `sepBy` (char '\n')只使用两个整数之间的\n,在成功解析四个数字之后,输入流中只有一个字符:

代码语言:javascript
复制
\n

decimal `sepBy` (char '\n')不能使用它,更糟糕的是它不会失败:sepBy可以使用任何东西并返回空列表。因此,它不会无限地解析任何东西,也不会终止。

为什么m1不产生1,2,3,4?

我也想知道!我想这与引信有关,也许你应该联系管道包的作者,他刚刚评论了你的问题。

票数 3
EN

Stack Overflow用户

发布于 2016-03-29 06:26:27

要回答有关m1的问题:当您使用CB.lines时,您将转换如下所示的输入:

代码语言:javascript
复制
["1\n2\n3\n4\n"]

转入:

代码语言:javascript
复制
["1", "2", "3", "4"]

然后,attoparsec解析"1",等待更多的输入,看到"2",等等。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36254752

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档