2016-01-16 8 views
9

मेरे पास निम्न कोड है, जिसे हटा दिया गया है और क्या मैं जितना संभव हो उतना कम सोचता हूं जिसमें कुछ अजीब व्यवहार होता है। कुछ डेटा को परिभाषित करने एक::नियंत्रण के साथ अप्रत्याशित स्मृति वृद्धि। मोनाड फोल्डएम

कोड दो स्रोत फ़ाइलों के होते हैं

module MyFunction where 

data MyFunction = 
    MyFunction { 
     functionNumber :: Int, 
     functionResult :: IO String 
     } 

makeMyFunction :: Show a => Int -> IO a -> MyFunction 
makeMyFunction number result = MyFunction { 
    functionNumber = number, 
    functionResult = result >>= return . show } 

और अन्य मुख्य है:

module Main (main) where 

import System.CPUTime (getCPUTime) 
import Data.List (foldl') 
import Data.Foldable (foldlM) 
import Control.Monad (foldM) 
import MyFunction 

exampleFunction = do 
    --let x = foldl' (\a b -> a `seq` (a + b)) 0 [1..20000000]  -- This works 
    --x <- foldlM (\a b -> a `seq` return (a + b)) 0 [1..20000000] -- This works (*) 
    x <- foldM (\a b -> a `seq` return (a + b)) 0 [1..20000000] -- This doesn't 
    print x 
    return() 

runFunction fn = do 
    result <- functionResult fn 
    duration <- getCPUTime 
    if result /= "()" 
     then putStrLn "" 
     else return() 
    putStrLn (show (fromIntegral duration/(10^9)) ++ "ms") 
    return fn 

main = do 
    runFunction (makeMyFunction 123 exampleFunction) 
    return() 

कोड के रूप में ऊपर (GHC 7.10.3 का उपयोग कर संकलित डिफ़ॉल्ट झंडे के साथ स्टैक 1.0.0 के साथ) मेमोरी उपयोग (1 जीबी से अधिक) में तेजी से वृद्धि हुई है, और आमतौर पर 3.3 सेकंड लेती है।

  • उपयोग समस्या लाइन
  • से runFunction

स्मृति के उपयोग किसी भी लाइन बाहर ले करने के लिए टिप्पणी की किसी एक विकल्प:

अगर मैं उदाहरण के लिए, कोड के लिए एक परिवर्तन करने न्यूनतम रहेगा, और केवल 1 सेकंड लेता है।

मुझे लगता है कि एक विशेषता मुझे आश्चर्यजनक है कि foldM को foldlM (जहां तक ​​मुझे पता है foldM = foldlM) समस्या को हल करता है।

कोड में परिवर्तन भी करना जो मुझे नहीं दिखता है, कोड की समस्या रेखाओं से कोई संबंध भी समस्या को हल करता है। उदाहरण के लिए अंतिम putStrLn को हटा रहा है।

एक और विषमता है कि अगर मैं मुख्य मॉड्यूल में myfunction मॉड्यूल विलय, जबकि यह समस्या हल नहीं होती, यह वास्तव में foldlM का कारण बनता है अत्यधिक स्मृति का उपयोग foldM के रूप में व्यवहार करने के लिए है।

वास्तविक कोड है कि इस से आया में, मैं एक बड़ी संख्या exampleFunction रों है, और वहाँ काफी अधिक Main कोड है, और हर बार मैं कार्यों से अस्पष्टीकृत स्मृति के उपयोग की इस तरह सामना करते हैं, कि आम तौर पर हल किया जा सकता किसी तरह के वूडू द्वारा।

मैं व्यवहार के लिए एक स्पष्टीकरण की तलाश में हूं। अगर मुझे पता है कि ऐसा क्यों होता है तो मैं इसे टालने में देख सकता हूं। क्या यह एक संकलक मुद्दा हो सकता है, या शायद मेरे हिस्से पर एक गलतफहमी हो सकती है?

(*) मैंने द्वितीयक समस्या को हाइलाइट किया है जो समान स्मृति वृद्धि को foldlM के साथ घटित करता है।

+4

तथ्य यह है कि मॉड्यूल के बीच चीजें चलाना व्यवहार को प्रभावित करता है * दृढ़ता से * सुझाव देता है कि जीएचसी का इनलाइनर शामिल है। सबसे अधिक संभावना है कि इनलाइनिंग द्वारा सक्षम कुछ परिवर्तन या तो * मदद * या * आपको * चोट पहुंचा रहा है। – dfeuer

+0

एक असंबंधित मुद्दा उदाहरण में आपका अंकगणितीय है फ़ंक्शन को इंटीजर में डिफॉल्ट किया जा रहा है जो काफी धीमा होगा। '-वॉल' चालू करें। – jberryman

+0

@ जेबरीमैन उदाहरण फ़ंक्शन का उदाहरण केवल उदाहरण होना है - स्मृति वृद्धि को दिखाने के लिए। – pticawr

उत्तर

3

यहाँ Foldable.hs से foldlM है (GHC)

-- | Monadic fold over the elements of a structure, 
-- associating to the left, i.e. from left to right. 
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b 
foldlM f z0 xs = foldr f' return xs z0 
    where f' x k z = f z x >>= k 

और foldM से Monad.hs

foldM   :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b 
{-# INLINEABLE foldM #-} 
{-# SPECIALISE foldM :: (a -> b -> IO a) -> a -> [b] -> IO a #-} 
{-# SPECIALISE foldM :: (a -> b -> Maybe a) -> a -> [b] -> Maybe a #-} 
foldM   = foldlM 

मैं एक अलग मॉड्यूल टेस्ट करने के लिए इन परिभाषाओं रखा जाता है और साथ और इनलाइन/SPESIALISE बिना निष्पादन का परीक्षण किया लाइनों। जो कुछ भी कारण है, विशेष निर्देशों को छोड़कर मदद मिली और निष्पादन समय और स्मृति उपयोग foldlM के साथ था।

थोड़ा और अधिक खुदाई, को हटाने लाइन के बाद

{-# SPECIALISE foldM :: (a -> b -> IO a) -> a -> [b] -> IO a #-} 

सबसे प्रभावित।

+3

कारण यह है कि 'विशेषीकृत' चिह्नित चीजों को दिए गए प्रकार के लिए विशिष्ट संकलित किया गया है, और जब उस प्रकार का उपयोग उपयोग साइटों पर देखा जाता है तो विशेष संस्करण का उपयोग किया जाता है; जीएचसी (आमतौर पर?) * बजाय * इनलाइनिंग पर विचार नहीं करता है। 'फोल्डएम' के रूप में सरल कुछ के लिए, विशेषज्ञता सामान्य रूप से इनलाइनिंग से भी बदतर लगती है, इसलिए उन प्रागम्स को हटा दिया जाना चाहिए। – dfeuer

+0

@dfeuer; जे.जे. : विशेषज्ञता को हटाने के दौरान एक समस्या हल होती है (उपरोक्त स्रोत फ़ाइलों का उपयोग करते समय)। क्या आप समझा सकते हैं कि स्रोत फ़ाइलों को एक में विलय करते समय समस्या क्यों आती है, लेकिन दोनों फ़ोल्डएम और फ़ोल्डएमएम मेमोरी उपयोग वृद्धि को दिखाती है? – pticawr

+0

@pticawr अनुकूलन ध्वज के बिना '-O1'? –

संबंधित मुद्दे