2013-08-02 12 views
16

मैंने इस छोटे से प्रोग्राम को बनाया जो लंबे समय से चलने वाले थंक बनाता है जो अंततः अपवाद के साथ विफल रहता है। फिर, एकाधिक धागे इसका मूल्यांकन करने का प्रयास करते हैं।यदि एक अपवाद में एक थंक परिणाम, तो थंक के परिणाम के रूप में अपवाद रखा जाता है?

import Control.Monad 
import Control.Concurrent 
import Control.Concurrent.MVar 

main = do 
    let thunk = let p = product [1..10^4] 
       in if p `mod` 2 == 0 then error "exception" 
             else() 
    children <- replicateM 2000 (myForkIO (print thunk)) 
    mapM_ takeMVar children 

-- | Spawn a thread and return a MVar which can be used to wait for it. 
myForkIO :: IO() -> IO (MVar()) 
myForkIO io = do 
    mvar <- newEmptyMVar 
    forkFinally io (\_ -> putMVar mvar()) 
    return mvar 

धागे की संख्या में वृद्धि स्पष्ट रूप से गणना है, जो पता चलता है कि एक असफल thunk परिणाम के रूप में अपवाद रखता है पर कोई प्रभाव नहीं है। क्या यह सच है? क्या यह व्यवहार कहीं भी दस्तावेज/निर्दिष्ट है?

अद्यतन:

forkFinally io (\e -> print e >> putMVar mvar()) 

करने के लिए forkFinally लाइन बदलने की पुष्टि करता है कि प्रत्येक धागा अपवाद के साथ विफल रहता है।

+1

अपवाद * अभिव्यक्ति का मान है। अभिव्यक्ति का मूल्यांकन कई बार कर सकता है? – Carl

+0

@ करल मुझे संदेह है, लेकिन मैं निश्चित होना चाहता हूं। यह बार-बार मूल्य को पुन: सम्मिलित करने का भी प्रयास कर सकता है। –

+0

मुझे जीएचसी आंतरिक पता है, अन्यथा मैं 'ghc-heap-view' जैसे टूल नहीं बना सका, इसलिए मुझे यकीन नहीं है कि आपको और क्या चाहिए। क्या आप कृपया अपने प्रश्न को स्पष्ट कर सकते हैं यदि मेरा उत्तर पर्याप्त सहायक नहीं है? –

उत्तर

12

ghc-heap-view लाइब्रेरी का उपयोग करके जीएचसी वास्तव में यह कैसे करता है यह दिखाकर मुझे इस प्रश्न का उत्तर दें। आप इसे ghc-vis के साथ पुन: पेश कर सकते हैं और अच्छी तस्वीरें प्राप्त कर सकते हैं।

मैंने कहीं एक अपवाद मान के साथ एक डेटा संरचना बना कर शुरूआत: कम से

Prelude> :script /home/jojo/.cabal/share/ghc-heap-view-0.5.1/ghci 
Prelude> let x = map ((1::Int) `div`) [1,0] 

पहले यह विशुद्ध रूप से एक thunk है (है कि विभिन्न प्रकार के वर्गों को शामिल करने लगता है):

Prelude> :printHeap x 
let f1 = _fun 
in (_bco [] (_bco (D:Integral (D:Real (D:Num _fun _fun _fun _fun _fun _fun _fun) (D:Ord (D:Eq _fun _fun) _fun _fun _fun _fun _fun _fun _fun) _fun) (D:Enum _fun _fun f1 f1 _fun _fun _fun _fun) _fun _fun _fun _fun _fun _fun _fun) _fun) _fun)() 

अब मैं गैर-अपवाद-फेंकने वाले हिस्सों का मूल्यांकन करें:

Prelude> (head x, length x) 
(1,2) 
Prelude> System.Mem.performGC 
Prelude> :printHeap x 
[I# 1,_thunk (_fun (I# 1)) (I# 0)] 

सूची का दूसरा तत्व स्थिर है मैं बस एक "सामान्य" थंक। अब मैं इस का मूल्यांकन, एक अपवाद मिलता है, और फिर इसे देख:

Prelude> last x 
*** Exception: divide by zero 
Prelude> System.Mem.performGC 
Prelude> :printHeap x 
[I# 1,_thunk (SomeException (D:Exception _fun (D:Show _fun _fun _fun) _fun _fun) DivideByZero())] 

अब आप इसे एक thunk संदर्भ देता है एक SomeException वस्तु है देख सकते हैं। SomeException डेटा कन्स्ट्रक्टर के पास forall e . Exception e => e -> SomeException टाइप है, इसलिए कन्स्ट्रक्टर का दूसरा पैरामीटर DivideByZeroArithException अपवाद का कन्स्ट्रक्टर है, और पहले पैरामीटर संबंधित Exception प्रकार क्लास इंस्टेंस है।

यह थंक किसी अन्य हास्केल मान की तरह ही पारित किया जा सकता है और यदि मूल्यांकन किया जाता है, तो अपवाद को फिर से उठाएं। और, किसी भी अन्य मूल्य की तरह, अपवाद साझा किया जा सकता:

Prelude> let y = (last x, last x) 
Prelude> y 
(*** Exception: divide by zero 
Prelude> snd y 
*** Exception: divide by zero 
Prelude> System.Mem.performGC 
Prelude> :printHeap y 
let x1 = SomeException (D:Exception _fun (D:Show _fun _fun _fun) _fun _fun) DivideByZero() 
in (_thunk x1,_thunk x1) 

ही बातें धागे और MVars, वहाँ कुछ खास नहीं के साथ हुआ।

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