Ich bin ein Haskell Anfänger und dachte, das wäre eine gute Übung. Ich habe eine Zuordnung wo I-Datei in einem Thread A lesen müssen, um die Datei in Zeilen Gewinde B_i handhaben, und die Ausgangs dann die Ergebnisse in Gewinde C.Begrenzung der Speichernutzung beim Lesen von Dateien
I dies bereits weit umgesetzt haben, aber eine der Anforderungen ist, dass wir nicht vertrauen können, dass die gesamte Datei in den Speicher passt. Ich hatte gehofft, dass faule IO und Garbage Collector würde dies für mich tun, aber leider die Speichernutzung steigt und steigt weiter.
Der Leser Thread (A) liest die Datei mit readFile
, die dann gezippt wird mit Zeilennummern und in Just gewickelt. Diese gezippten Zeilen werden dann zu Control.Concurrent.Chan
geschrieben. Jeder Consumer-Thread B hat seinen eigenen Kanal.
Jeder Verbraucher liest seinen eigenen Kanal, wenn es Daten hat und wenn der Regex übereinstimmt, wird es auf seinen eigenen entsprechenden Ausgangskanal innerhalb von Maybe (bestehend aus Listen) ausgegeben.
Der Drucker überprüft den Ausgabekanal jedes B-Threads. Wenn keine die Ergebnisse (Zeile) ist nichts, wird die Zeile gedruckt. Da an dieser Stelle kein Hinweis auf die älteren Zeilen sein sollte, dachte ich, dass der Müll Sammler diese Zeilen freigeben könnte, aber ach, ich schein in das falsche hier zu sein.
Die .lhs Datei ist in hier: http://gitorious.org/hajautettujen-sovellusten-muodostamistekniikat/hajautettujen-sovellusten-muodostamistekniikat/blobs/master/mgrep.lhs
Die Frage ist also, wie beschränke ich die Speichernutzung oder der Müll Sammler erlauben, um die Linien zu entfernen.
Snippets wie angefordert. Hoffentlich wird Einrücken nicht zu stark zerstört :)
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
BoundedChan auf Hackage für genau diese Art der Verwendung ist. –
Danke Tom und Sciv. Ich werde versuchen, es zu implementieren und als eine Antwort zu markieren, wenn es funktioniert – Masse