Ограничение использования памяти, когда чтение файлов

Я новичок в Haskell и подумал, что это будет хорошее упражнение. у меня есть назначение, где мне нужно прочитать файл в потоке A, обработать строки файла в потоках B_i, а затем выводить результаты в потоке C.

Я уже реализовал это, но одно из требований состоит в том, что мы не могу поверить, что весь файл умещается в памяти. Я надеялся, что ленивый IO и сборщик мусора сделали бы это за меня, но, увы, использование памяти продолжает расти и расти.

Поток чтения (A) читает файл с readFile , который затем архивируется с номерами строк и завернутый в Just. Затем эти заархивированные строки записываются на Control.Concurrent.Chan . Каждый потребительский поток B имеет свой собственный канал.

Каждый потребитель читает свой собственный канал, когда у него есть данные и если регулярное выражение совпадений, он выводится в их собственный соответствующий выходной канал, завернутый внутри Maybe (составлен из списков).

Принтер проверяет выходной канал каждого из потоков B. Если ни один из результат (строка) - Ничего, строка печатается. Поскольку на данный момент не должно быть ссылки на старые строчки, думал, что фигня коллекционер мог бы выпустить эти строки, но, увы, мне кажется, здесь неправильно.

Файл .lhs находится здесь: http://gitorious.org/hajautettujen-sovellusten-muodostamistekniikat/hajautettujen-sovellusten-muodostamistekniikat/blobs/master/mgrep.lhs

Вопрос в том, как разрешить использование мусора или разрешить использование памяти сборщик для удаления строк.

Фрагменты согласно запросу. Надеюсь, отступы не так сильно разрушены:)

data Global = Global {done :: MVar Bool, consumers :: Consumers}
type Done = Bool
type Linenum = Int
type Line = (Linenum, Maybe String)
type Output = MVar [Line]
type Input = Chan Line
type Consumers = MVar (M.Map ThreadId (Done, (Input, Output)))
type State a = ReaderT Global IO a


producer :: [Input] -> FilePath -> State ()
producer c p = do
  liftIO $ Main.log "Starting producer"
  d <- asks done
  f <- liftIO $ readFile p
  mapM_ (\l -> mapM_
    (liftIO . flip writeChan l) c)
    $ zip [1..] $ map Just $ lines f
  liftIO $ modifyMVar_ d (return . not)

printer :: State ()
printer = do
  liftIO $ Main.log "Starting printer"
  c <- (fmap (map (snd . snd) . M.elems)
    (asks consumers >>= liftIO . readMVar))
  uniq' c
  where head' :: Output -> IO Line
    head' ch = fmap head (readMVar ch)

    tail' = mapM_ (liftIO . flip modifyMVar_
        (return . tail))

    cont ch = tail' ch >> uniq' ch

    printMsg ch = readMVar (head ch) >>=
        liftIO . putStrLn . fromJust . snd . head

    cempty :: [Output] -> IO Bool
    cempty ch = fmap (any id)
        (mapM (fmap ((==) 0 . length) . readMVar ) ch)

    {- Return false unless none are Nothing -}
    uniq :: [Output] -> IO Bool
    uniq ch = fmap (any id . map (isNothing . snd))
        (mapM (liftIO . head') ch)

    uniq' :: [Output] -> State ()
    uniq' ch = do
      d <- consumersDone
      e <- liftIO $ cempty ch
      if not e
        then  do
          u <- liftIO $ uniq ch
          if u then cont ch else do
        liftIO $ printMsg ch
        cont ch
          else unless d $ uniq' ch

5
задан Bill the Lizard 16 December 2012 в 16:01
поделиться