2012-09-09 18 views
8

सी # एआई प्रोग्राम के लिए मैं सबसे अच्छा अगला कदम खोजने के लिए एक रिकर्सिव कॉल का उपयोग करता हूं (वर्तमान बोर्ड स्थिति को स्टोर करने के लिए 30x30 ऐरे का उपयोग करके)। मैं प्रत्येक कदम के लिए, मैं देखना चाहता हूं कि नए बोर्ड राज्य से मैं कौन सी संभावित चाल कर सकता हूं, सबसे अच्छा होगा ... और तब तक जब तक मैं या तो "खेल का अंत" स्थिति तक नहीं पहुंच जाता (उसमें आगे कोई चाल संभव नहीं है राज्य) या एक टाइमर प्रक्रिया को रोकता है और कोई और रिकर्सिव कॉल नहीं किया जाता है (और "सर्वश्रेष्ठ" ज्ञात स्थिति वापस आती है)। यह सिर्फ यह बताने के लिए कि मुझे रिकर्सन का उपयोग क्यों करना चाहिए (यह पूंछ रिकर्सन नहीं है) और मैं एक एकल (वैश्विक) बोर्ड स्थिति का उपयोग नहीं कर सकता, लेकिन वर्तमान स्थिति से संभवतः सभी बोर्ड राज्यों को खोजना चाहिए।रिकर्सिव कॉल से पहले उपलब्ध स्टैक आकार की जांच करने का कोई तरीका है? (सी #)

(कभी-कभी) मुझे एक सिस्टम मिलता है। StackOverflowException। अगली रिकर्सिव कॉल से पहले उपलब्ध स्टैक स्पेस को देखने का कोई तरीका है? तब मैं वर्तमान स्थिति को "अब तक की सबसे अच्छी स्थिति" के रूप में वापस कर सकता हूं और अगली रिकर्सिव कॉल नहीं कर सकता। अर्थात। जब उपलब्ध ढेर बहुत छोटा हो जाता है तो इसे बेस केस के रूप में भी गिना जाना चाहिए।

पाठ्यक्रम का दूसरा विकल्प, प्रत्येक रिकर्सिव कॉल को एक कोशिश में डाल सकता है .. ब्लॉक ब्लॉक करें और सिस्टम को संभालें। स्टैक ओवरव्लो एक्सेप्शन इसे बेस केस के रूप में उपयोग करके?

+5

अपना कोड फिर से डिजाइन करें? एक स्टैक ओवरफ्लो एक बग या खराब (सी #) कोड का संकेत है। स्टैक ओवरफ्लो को ट्रिगर करने के लिए आपको रिकर्सिव कॉल की पागल राशि की आवश्यकता होती है। यदि आप वास्तव में ऐसा करना चाहते हैं तो F # की तरह पूंछ-कॉल का समर्थन करने वाली एक कार्यात्मक भाषा का उपयोग करें। सी # इसके लिए डिज़ाइन नहीं किया गया है। – Dykam

+0

"यदि आप एक रिकर्सिव विधि या कई स्टैक स्पेस का उपयोग करने की योजना बना रहे हैं, तो आपको RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup विधि का उपयोग करना होगा।" - http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.probeforsufficientstack.aspx – DavidO

उत्तर

1

यदि आप वास्तव में उस पथ पर जाना चाहते हैं तो आप EnsureSufficientExecutionstack विधि का उपयोग कर सकते हैं।

जैसा कि अन्य ने इंगित किया, .NET 2 से शुरू हुआ।0 आप नहीं कर सकते पकड़ एक StackOverflowException, तथापि, MSDN प्रलेखीकरण से आप जानते हैं कि पिछले विधि निम्नलिखित व्यवहार है:

सुनिश्चित करता है कि शेष ढेर अंतरिक्ष काफी बड़ी औसत .नेट फ्रेमवर्क समारोह निष्पादित करने के लिए है।

जब ढेर इस विधि के अनुसार इतना बड़ा नहीं है तो यह एक InsufficientExecutionStackException अपवाद है कि आप पकड़ कर सकते हैं फेंक देते हैं।

+0

क्या आपने कोशिश की है? "यह सुनिश्चित करता है कि शेष स्टैक स्पेस औसत .NET Framework फ़ंक्शन निष्पादित करने के लिए पर्याप्त है"। ओपीएस मामले में पर्याप्त जगह कभी नहीं हो सकती है - यह तरीका * ज्ञात * कैसे होगा? –

+0

प्रत्येक रिकर्सन स्तर को फिर से जांचना होगा, नहीं? – DavidO

+0

वह हिस्सा एमएसडीएन दस्तावेज से है, मुझे इसके लिए एक उद्धरण जोड़ना चाहिए था, मैं जवाब अपडेट कर दूंगा। जैसा कि डेविडो ने बताया, वैध कार्यवाही के लिए चेक प्रत्येक चरण में किया जाना चाहिए। –

2

दरअसल, सिस्टम गतिशील रूप से स्टैक आकार का विस्तार करेगा, क्या यह मौजूदा स्टैक पर स्थान से बाहर हो जाना चाहिए। तो, भले ही आप स्टैक के आकार का परीक्षण कर सकें, यह वास्तव में कोई फर्क नहीं पड़ता।

http://msdn.microsoft.com/en-us/library/windows/desktop/ms686774(v=vs.85).aspx विवरण

प्रणाली, सुरक्षित ढेर स्मृति से अतिरिक्त पृष्ठों के रूप में वे की जरूरत है करता है जब तक या तो ढेर आरक्षित आकार शून्य से एक पृष्ठ (जो एक गार्ड पेज ढेर अतिप्रवाह को रोकने के लिए के रूप में प्रयोग किया जाता है पहुँचता है) या सिस्टम स्मृति पर इतना कम है कि आपरेशन में विफल रहता है "है

कौन कह रहा है कि, इससे पहले कि प्रत्यावर्तन होता है, ढेर एक आकार है,। और अगर प्रत्यावर्तन एक ढेर अतिप्रवाह का कारण बनता है, ढेर एक है नया आकार जब हुआ।

चूंकि आप टर्मिनल रिकर्सन के बजाय StackOverflowException नहीं पकड़ सकते हैं, तो आप पूंछ रिकर्सन का उपयोग कर सकते हैं। http://www.thomaslevesque.com/2011/09/02/tail-recursion-in-c/

+0

"(कभी-कभी) मुझे एक सिस्टम मिलता है। स्टैक ओवरव्लो एक्सेप्शन।" (यह समझाने के लिए उपयोगी हो सकता है।) – DavidO

+0

@ डेविडो, यह कहना नहीं है कि रिकर्सन चालू होने पर स्टैक बढ़ाने के बावजूद, यह ढेर का विस्तार करने के लिए स्मृति से बाहर हो गया। –

+0

यह वर्तमान बोर्ड की स्थिति पर निर्भर करता है। अगर उत्तर पर्याप्त जल्दी पाया जाता है (मूल मामला जल्दी पाया जाता है), तो मुझे आमतौर पर समस्या नहीं मिलती है। –

2

आप प्रत्यावर्तन के बजाय एक कतार + लूप (Queue<TNode> + while (queue.MoveNext())) का उपयोग करें और कतार के आकार को सीमित कर सकता है: नीचे दिए गए लिंक पूंछ recusion में टर्मिनल recusion परिवर्तित करने पर कुछ अच्छा विस्तार प्रदान करता है।

या आप विधि के लिए खुली कॉल पर भरोसा कर सकते हैं और इस तरह से रिकर्सन को सीमित कर सकते हैं। (प्रविष्टियों की गणना करें और निकालें और रिकॉर्ड्स दर्ज न करें अगर प्रविष्टियां मौजूद हैं> maxOpenCalls)।

1

नेट 2 के साथ शुरू आप StackOverflowException नहीं पकड़ सकते ...

एक ही रास्ता निर्धारित करने के लिए पहले से ही साधन प्रयोग किया जाता है कि कैसे अपने ढेर के ज्यादा असुरक्षित कोड जो मैं दृढ़ता के खिलाफ ... बेहतर एक स्पष्ट का उपयोग की सलाह का उपयोग करने के ढेर-आधारित Stack<T>

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