2012-01-27 20 views
5

मैं एक प्रकार की डेटाबेस लाइब्रेरी लिख रहा हूं। मूलभूत निर्यात यह निम्न है:एसिंक्रोनस अपवादों का नेस्टेड मास्किंग

withDatabase :: FilePath -> (DBHandle -> IO a) -> IO a 

जो स्वचालित रूप से डेटाबेस हैंडल के जीवनकाल का प्रबंधन करता है।

आंतरिक रूप से, withDatabaseसे नियंत्रण का उपयोग करता है। नियंत्रण 0 अपवाद

withDatabase path f = bracket (openDatabase path) closeDatabase f 

मेरी विशिष्ट मामले में, openDatabase कुछ महत्वपूर्ण आई/ओ प्रदर्शन कर सकते हैं और इस तरह एक लंबे समय के लिए ब्लॉक। इस कारण से, मैं इसके कुछ हिस्सों को असीमित अपरिवर्तित अपवादों के साथ चलाने के लिए चाहता हूं। एक (सरलीकृत) कार्यान्वयन हो सकता है:

openDatabase :: FilePath -> IO DBHandle 
openDatabase path = mask $ \restore -> do 
         h <- openFile path ReadWriteMode 
         restore (doLongStuff h) `onException` (hClose h) 
         ... 
         return (DBHandle h) 

मुझे यकीन है कि इस कोड प्रभाव मैं इरादा उत्पादन नहीं कर रहा हूँ।

के withDatabase पर वापस नजर डालते हैं, इस बार अपनी परिभाषा के साथ bracket की जगह:

\- withDatabase 
\- mask 
    \- openDatabase 
    \- mask 
    \- restore 
    \- doLongStuff 

प्रलेखन के लिए:

withDatabase path f = mask $ \restore -> do 
    h <- openDatabase path 
    r <- restore (f h) `onException` closeDatabase h 
    _ <- closeDatabase h 
    return r 

निष्पादन में एक निश्चित बिंदु पर, कॉल स्टैक निम्न हो जाता है नियंत्रण। अपवाद मॉड्यूल में नेस्टेड कॉल के बारे में कुछ है mask:

ध्यान दें कि मुखौटा के तर्क को पारित करने वाली पुनर्स्थापना कार्रवाई अनिवार्य रूप से एसिंक्रोनस अपवादों को अनमास्क नहीं करती है, यह केवल मुखौटा स्थिति को संलग्न संदर्भ के लिए पुनर्स्थापित करती है। इस प्रकार यदि एसिंक्रोनस अपवाद पहले ही मास्क किए गए हैं, तो मास्क का उपयोग अपवादों को फिर से खोलने के लिए नहीं किया जा सकता है।

इस वर्णन की मेरी समझ यह है कि doLongStuff एसिंक्रोनस अपवादों के साथ काम करेगा, जैसा कि मैं चाहूंगा, अनब्लॉक किया गया था।

मेरा असली कोड में, मैं openFile है और न ही doLongStuff न स्थानांतरित नहीं कर सकते openDatabase से बाहर: वास्तव में, openDatabase फ़ाइलों के किसी भी संख्या को खोलने और/या पहले "निर्णय लेने से" जो संभाल यह withDatabase पर लौटने के लिए चाहता है विभिन्न मैं/ओएस प्रदर्शन कर सकते हैं । इस दबाव को देखते हुए, क्या doLongStuff को अवरुद्ध करने का कोई तरीका है भले ही यह नेस्टेड mask कॉल के अंदर चलने के लिए होता है?

उत्तर

0

doLongStuff डेटाबेस पर किया जा रहा है? यदि ऐसा है, तो यह पहले से ही व्यवधान हो सकता है। Interruptible Operations पर अनुभाग देखें, जिसमें कहा गया है कि कोई भी कार्य जो अवरुद्ध हो सकता है, जिसमें आईओओ करने वाले अधिकांश कार्यों को भी मुखौटा के दायरे में बाधित किया जा सकता है।

अगर doLongStuff व्यवधान कारक है या नहीं आप सुनिश्चित नहीं हैं कि (निर्भर करता है जो काम करता है इसे इस्तेमाल करता है), तो आप या तो allowInterrupt का उपयोग नकाबपोश कोड के भीतर async अपवाद के लिए मतदान कर सकते हैं, या वैकल्पिक रूप एक MVar का उपयोग डीबी से पढ़ने सिंक्रनाइज़ करने के लिए । यह काम करेगा क्योंकि अधिकांश MVar संचालन खुद को बाधित कर रहे हैं, जिससे बड़े कार्य को भी बाधित किया जा सकता है।

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