Tôi là người mới bắt đầu sử dụng Haskell và nghĩ rằng đây sẽ là bài tập tốt. Tôi có một bài tập nơi tôi cần đọc tệp trong chuỗi A, xử lý các dòng tệp trong chủ đề B_i, sau đó xuất kết quả trong chủ đề C.Hạn chế sử dụng bộ nhớ khi đọc các tệp
Tôi đã thực hiện điều này, nhưng một trong các yêu cầu là chúng tôi không thể tin tưởng rằng toàn bộ tệp phù hợp với bộ nhớ. Tôi đã hy vọng rằng lười biếng IO và thu gom rác sẽ làm điều này cho tôi, nhưng than ôi việc sử dụng bộ nhớ tiếp tục tăng và tăng.
Chuỗi trình đọc (A) đọc tệp với readFile
sau đó được nén với số dòng và được bao bọc trong Chỉ. Những dòng được nén sau đó được viết đến Control.Concurrent.Chan
. Mỗi chủ đề người tiêu dùng B có kênh riêng của mình.
Mỗi người tiêu dùng đọc kênh riêng của họ khi có dữ liệu và nếu regex kết quả phù hợp, kênh này được xuất cho kênh đầu ra tương ứng của riêng mình được bọc trong Có thể (được tạo thành danh sách).
Máy in kiểm tra kênh đầu ra của từng chuỗi B. Nếu không có kết quả (dòng) là Không có gì, dòng được in. Vì tại thời điểm này không nên có tham chiếu đến các dòng cũ hơn, tôi nghĩ rằng rác collector sẽ có thể phát hành những dòng này, nhưng tôi dường như ở trong sai ở đây.
File .lhs là ở đây: http://gitorious.org/hajautettujen-sovellusten-muodostamistekniikat/hajautettujen-sovellusten-muodostamistekniikat/blobs/master/mgrep.lhs
Vì vậy, câu hỏi là, làm thế nào để hạn chế việc sử dụng bộ nhớ, hoặc cho phép các bộ thu rác để loại bỏ các dòng.
Đoạn trích theo yêu cầu. Hy vọng rằng indenting không phải là quá xấu bị phá hủy :)
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 là trên hackage cho chính xác loại hình này sử dụng. –
Cảm ơn Tom và sciv. Tôi sẽ thử triển khai và đánh dấu câu trả lời nếu nó hoạt động – Masse