मैं हास्केल शुरुआती हूं और सोचा कि यह अच्छा अभ्यास होगा। मैं एक काम जहाँ मैं, एक धागा एक में फ़ाइल को पढ़ने B_i धागे में फ़ाइल लाइनों संभालने की ज़रूरत है, और फिर उत्पादन धागा सी में परिणामफ़ाइलों को पढ़ने के दौरान स्मृति उपयोग सीमित करना
मैं इतनी दूर पहले से ही लागू कर दिया है, लेकिन आवश्यकताओं में से एक है यह है कि हम भरोसा नहीं कर सकते कि पूरी फ़ाइल स्मृति में फिट बैठती है। मैं उम्मीद कर रहा था कि आलसी आईओ और कचरा कलेक्टर मेरे लिए यह करेगा, लेकिन स्मृति उपयोग बढ़ता और बढ़ता रहता है।
पाठक धागा (ए) readFile
के साथ फ़ाइल को पढ़ता है जिसे तब को लाइन संख्याओं के साथ ज़िपित किया जाता है और बस में लपेटा जाता है। ये ज़िपित लाइनें से Control.Concurrent.Chan
पर लिखी जाती हैं। प्रत्येक उपभोक्ता थ्रेड बी का अपना चैनल होता है।
प्रत्येक उपभोक्ता डेटा के समय अपने स्वयं के चैनल को पढ़ता है और यदि रेगेक्स मैचों, तो यह संभवतः (सूचियों से बने) के भीतर लिपटे अपने संबंधित आउटपुट चैनल पर आउटपुट किया जाता है।
प्रिंटर प्रत्येक बी थ्रेड के आउटपुट चैनल की जांच करता है। यदि में से कोई भी परिणाम (रेखा) कुछ भी नहीं है, तो रेखा मुद्रित होती है। चूंकि इस बिंदु पर पुरानी लाइनों का कोई संदर्भ नहीं होना चाहिए, मैंने सोचा कि कचरा कलेक्टर इन पंक्तियों को जारी करने में सक्षम होगा, लेकिन हां, मैं में गलत हूं।
.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
BoundedChan वास्तव में उपयोग की इस प्रकार के लिए hackage पर है। –
धन्यवाद टॉम और sciv। मैं इसे लागू करने का प्रयास करूंगा और अगर यह काम करता है तो उत्तर के रूप में चिह्नित होगा – Masse