나는 이것을 Haskell과 파이프 라이브러리의 초보자라고 말하고, 무엇이 test
함수에서이 프로그램의 높은 메모리 사용을 일으키는 지 알고 싶다. . deepseq
사용하지 않는 특히 내가 최종 결과까지 데 MyRecord 값의 축적을보고 있어요 test
에 r1
값을 생성하는 배에서이 Haskell 프로그램의 메모리 사용 이해하기
이 생산된다. ~ 500000 줄/230 MB의 샘플 데이터 세트에서 메모리 사용량은 1.5GB를 초과하여 증가합니다.
r2
값을 생성하는 폴드는 상수 메모리에서 실행됩니다.
내가 이해하고자하는 것입니다 :
최초의 배에 내 메모리 값의 빌드를 일으키는, 왜 그것을 해결하는 것deepseq
를 사용 할 수 무엇
1)? 항상 무작위로 물건을 던져서 deepseq
을 사용하여 일정한 메모리 사용량을 얻었지만 왜 작동 하는지를 알고 싶습니다. 을 사용하지 않고 상수 메모리 사용을 달성 할 수 있습니까?
2). 두 번째 폴드가 다른 경우 동일한 문제가 발생하지 않는 이유는 무엇입니까?
튜플 대신 정수로만 작업한다면 Pipees.Prelude에서 내장 함수 sum
을 사용할 수 있지만 결국에는 구문 분석 오류가 포함 된 두 번째 요소를 처리하려고합니다.
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Test where
import Control.Arrow
import Control.DeepSeq
import Control.Monad
import Data.Aeson
import Data.Function
import Data.Maybe
import Data.Monoid
import Data.Text (Text)
import Pipes
import qualified Pipes.Aeson as PA (DecodingError(..))
import qualified Pipes.Aeson.Unchecked as PA
import qualified Pipes.ByteString as PB
import qualified Pipes.Group as PG
import qualified Pipes.Parse as PP
import qualified Pipes.Prelude as P
import System.IO
import Control.Lens
import qualified Control.Foldl as Fold
data MyRecord = MyRecord
{ myRecordField1 :: !Text
, myRecordField2 :: !Int
, myRecordField3 :: !Text
, myRecordField4 :: !Text
, myRecordField5 :: !Text
, myRecordField6 :: !Text
, myRecordField7 :: !Text
, myRecordField8 :: !Text
, myRecordField9 :: !Text
, myRecordField10 :: !Int
, myRecordField11 :: !Text
, myRecordField12 :: !Text
, myRecordField13 :: !Text
} deriving (Eq, Show)
instance FromJSON MyRecord where
parseJSON (Object o) =
MyRecord <$> o .: "field1" <*> o .: "field2" <*> o .: "field3" <*>
o .: "field4" <*>
o .: "field5" <*>
o .: "filed6" <*>
o .: "field7" <*>
o .: "field8" <*>
o .: "field9" <*>
(read <$> o .: "field10") <*>
o .: "field11" <*>
o .: "field12" <*>
o .: "field13"
parseJSON x = fail $ "MyRecord: expected Object, got: " <> show x
instance ToJSON MyRecord where
toJSON _ = undefined
test :: IO()
test = do
withFile "some-file" ReadMode $ \hIn
{-
the pipeline is composed as follows:
1 a producer reading a file with Pipes.ByteString, splitting chunks into lines,
and parsing the lines as JSON to produce tuples of (Maybe MyRecord, Maybe
ByteString), the second element being an error if parsing failed
2 a pipe filtering that tuple on a field of Maybe MyRecord, passing matching
(Maybe MyRecord, Maybe ByteString) downstream
3 and a pipe that picks an Int field out of Maybe MyRecord, passing (Maybe Int,
Maybe ByteString downstream)
pipeline == 1 >-> 2 >-> 3
memory profiling indicates the memory build up is due to accumulation of
MyRecord "objects", and data types comprising their fields (mainly
Text/ARR_WORDS)
-}
-> do
let pipeline = f1 hIn >-> f2 >-> f3
-- need to use deepseq to avoid leaking memory
r1 <-
P.fold
(\acc (v, _) -> (+) <$> acc `deepseq` acc <*> pure (fromMaybe 0 v))
(Just 0)
id
(pipeline :: Producer (Maybe Int, Maybe PB.ByteString) IO())
print r1
hSeek hIn AbsoluteSeek 0
-- this works just fine as is and streams in constant memory
r2 <-
P.fold
(\acc v ->
case fst v of
Just x -> acc + x
Nothing -> acc)
0
id
(pipeline :: Producer (Maybe Int, Maybe PB.ByteString) IO())
print r2
return()
return()
f1
:: (FromJSON a, MonadIO m)
=> Handle -> Producer (Maybe a, Maybe PB.ByteString) m()
f1 hIn = PB.fromHandle hIn & asLines & resumingParser PA.decode
f2
:: Pipe (Maybe MyRecord, Maybe PB.ByteString) (Maybe MyRecord, Maybe PB.ByteString) IO r
f2 = filterRecords (("some value" ==) . myRecordField5)
f3 :: Pipe (Maybe MyRecord, d) (Maybe Int, d) IO r
f3 = P.map (first (fmap myRecordField10))
filterRecords
:: Monad m
=> (MyRecord -> Bool)
-> Pipe (Maybe MyRecord, Maybe PB.ByteString) (Maybe MyRecord, Maybe PB.ByteString) m r
filterRecords predicate =
for cat $ \(l, e) ->
when (isNothing l || (predicate <$> l) == Just True) $ yield (l, e)
asLines
:: Monad m
=> Producer PB.ByteString m x -> Producer PB.ByteString m x
asLines p = Fold.purely PG.folds Fold.mconcat (view PB.lines p)
parseRecords
:: (Monad m, FromJSON a, ToJSON a)
=> Producer PB.ByteString m r
-> Producer a m (Either (PA.DecodingError, Producer PB.ByteString m r) r)
parseRecords = view PA.decoded
resumingParser
:: Monad m
=> PP.StateT (Producer a m r) m (Maybe (Either e b))
-> Producer a m r
-> Producer (Maybe b, Maybe a) m()
resumingParser parser p = do
(x, p') <- lift $ PP.runStateT parser p
case x of
Nothing -> return()
Just (Left _) -> do
(x', p'') <- lift $ PP.runStateT PP.draw p'
yield (Nothing, x')
resumingParser parser p''
Just (Right b) -> do
yield (Just b, Nothing)
resumingParser parser p'
확인 haskell 태그 정보 섹션을 참조 하시고, 바이너리를 컴파일하고 실행하는 방법을 게시 하시길 바랍니다. – jberryman
왜냐하면'seq (그냥 정의되지 않음) =()'하지만'seq (undefined :: Int)() = undefined' – user2407038
'forceMaybe Nothing = Nothing; forceMaybe x @ (Just! _) = x'. – dfeuer