Я новичок в 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