2010-02-25 4 views
6

समारोह के दूसरे फोन पर हमेशा के लिए चलाता है:SBCL समारोह

एक सूची lst वापसी को देखते हुए वास्तव में लंबाई कश्मीर की सूची की सामग्री है, जो सूची की लंबाई के चूक यदि उपलब्ध नहीं के सभी क्रमपरिवर्तन।

(defun permute (lst &optional (k (length lst))) 
    (if (= k 1) 
    (mapcar #'list lst) 
    (loop for item in lst nconcing 
    (mapcar (lambda (x) (cons item x)) 
      (permute (remove-if (lambda (x) (eq x item)) lst) 
         (1- k)))))) 
समस्या

: मैं SBCL से जुड़ा Emacs में कीचड़ उपयोग कर रहा हूँ, मैं बहुत अधिक अनुकूलन अभी तक नहीं किया है। समारोह छोटे इनपुट जैसे lst = '(1 2 3 4 5 6 7 8) के = 3 पर ठीक काम करता है, जिसका प्रयोग ज्यादातर अभ्यास में किया जाएगा। हालांकि जब मैं इसे लगातार दो बार एक बड़े इनपुट के साथ बुलाता हूं तो दूसरी कॉल कभी वापस नहीं आती है और एसबीसीएल शीर्ष पर भी दिखाई नहीं देता है। ये परिणाम आरपीएल:

CL-USER> (time (nth (1- 1000000) (permute '(0 1 2 3 4 5 6 7 8 9)))) 
Evaluation took: 
12.263 seconds of real time 
12.166150 seconds of total run time (10.705372 user, 1.460778 system) 
[ Run times consist of 9.331 seconds GC time, and 2.836 seconds non-GC time. ] 
99.21% CPU 
27,105,349,193 processor cycles 
930,080,016 bytes consed 

(2 7 8 3 9 1 5 4 6 0) 
CL-USER> (time (nth (1- 1000000) (permute '(0 1 2 3 4 5 6 7 8 9)))) 

और यह दूसरी कॉल से कभी वापस नहीं आता है। मैं केवल अनुमान लगा सकता हूं कि किसी कारण से मैं कचरा कलेक्टर के लिए कुछ भयानक कर रहा हूं लेकिन मैं नहीं देख सकता। क्या किसी के पास कोई विचार है?

+0

ऐसा होने पर आपके * अवरुद्ध-लिस्प * बफर में कुछ भी दिलचस्प है? – Xach

+0

क्यों एसबीसीएल को बाधित नहीं करते हैं और बैकट्रैक को देखते हैं कि यह क्या करता है? –

+0

उत्तर देने वाले सभी लोगों के लिए एक सामान्य प्रश्न के रूप में।ऐसा लगता है कि मैं जो कचरा बना रहा हूं वह समस्या है। क्या इस तरह की चीजों को पाने के तरीके के बारे में कोई अच्छा लेख है? मैंने कुछ चीजें की हैं जिन्हें मैंने सोचा था लेकिन सार्वभौमिक रूप से उन्होंने वास्तव में इसे और भी बदतर बना दिया है। – asm

उत्तर

4

एक चीज़ जो आपके कोड में गलत है वह ईक्यू का उपयोग है। ईक्यू पहचान के लिए तुलना करता है।

ईक्यू संख्याओं की तुलना करने के लिए नहीं है। दो संख्याओं का ईक्यू सच या गलत हो सकता है।

यदि आप पहचान, तुलना मूल्य या पात्रों से तुलना करना चाहते हैं तो ईक्यूएल का उपयोग करें। ईक्यू नहीं

असल

(remove-if (lambda (x) (eql x item)) list) 

सिर्फ

(remove item list) 

अपने कोड EQ बग अर्थ हो सकता है कि दूसरे स्थान पर रखना वास्तव में एक नंबर सूची से हटा बिना पुनरावर्ती कॉल में कहा जाता हो जाता है के लिए है।

इसके अलावा, मुझे लगता है कि एसबीसीएल स्मृति प्रबंधन के साथ बस व्यस्त है। मेरे मैक पर एसबीसीएल ने बहुत सारी मेमोरी (एक जीबी से अधिक) हासिल की और कुछ करने में व्यस्त था। कुछ समय बाद परिणाम गणना की गई थी।

आपका रिकर्सिव फ़ंक्शन बड़ी मात्रा में 'कचरा' उत्पन्न करता है। LispWorks कहते हैं: 1360950192 बाइट्स

शायद आप एक अधिक कुशल कार्यान्वयन के साथ आ सकते हैं?

अद्यतन: कचरा

लिस्प कुछ स्वचालित स्मृति प्रबंधन प्रदान करता है, लेकिन यह है कि प्रोग्रामर अंतरिक्ष प्रभाव के बारे में सोच से मुक्त नहीं है।

लिस्प मेमोरी आवंटित करने के लिए एक ढेर और ढेर दोनों का उपयोग करता है। ढेर शायद जीसी के लिए कुछ तरीकों से संरचित हो - उदाहरण के लिए पीढ़ियों, आधा रिक्त स्थान और/या क्षेत्रों में। सटीक कचरा कलेक्टर और 'रूढ़िवादी' कचरा कलेक्टर हैं (इंटेल मशीनों पर एसबीसीएल द्वारा उपयोग किया जाता है)।

एक कार्यक्रम चलाता है जब हम विभिन्न प्रभाव देख सकते हैं:

  1. सामान्य पुनरावर्ती प्रक्रियाओं ढेर पर अंतरिक्ष का आवंटन। समस्या: ढेर का आकार आमतौर पर तय किया जाता है (भले ही कुछ लिस्पस इसे एक त्रुटि हैंडलर में बढ़ा सकते हैं)।

  2. एक प्रोग्राम बड़ी मात्रा में स्मृति आवंटित कर सकता है और एक बड़ा परिणाम लौटा सकता है। PERMUTE ऐसा एक समारोह है। यह बहुत बड़ी सूचियां वापस कर सकता है।

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

हालांकि, और भी समस्याएं हैं। लेकिन उपरोक्त में से प्रत्येक के लिए लिस्प प्रोग्रामर (और कचरा संग्रह के साथ एक भाषा कार्यान्वयन का उपयोग करने वाले हर दूसरे प्रोग्रामर) को सीखना है कि इससे कैसे निपटना है।

  1. पुनरावृत्ति के साथ पुनरावृत्ति बदलें। पूंछ रिकर्सन के साथ रिकर्सन बदलें।

  2. केवल आवश्यक परिणाम का हिस्सा लौटें और पूर्ण समाधान उत्पन्न न करें। यदि आपको एन-वें क्रमपरिवर्तन की आवश्यकता है, तो उस पर गणना करें और सभी क्रमपरिवर्तन नहीं। मांग पर गणना की गई आलसी डेटास्ट्रक्चर का प्रयोग करें। SERIES जैसे कुछ का उपयोग करें, जो धारा-जैसी, लेकिन कुशल, गणना का उपयोग करने की अनुमति देता है। एसआईसीपी, पीएआईपी, और अन्य उन्नत लिस्प पुस्तकें देखें।

  3. संसाधन प्रबंधक के साथ स्मृति का पुन: उपयोग करें। वस्तुओं को आवंटित करने के बजाए बफर का पुन: उपयोग करें। क्षणिक (अल्पकालिक) वस्तुओं को इकट्ठा करने के लिए विशेष समर्थन के साथ एक कुशल कचरा कलेक्टर का उपयोग करें। कभी-कभी यह नई वस्तुओं को आवंटित करने के बजाय वस्तुओं को विनाशकारी रूप से संशोधित करने में भी मदद कर सकता है।

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

+0

क्या मैं यह सोचने में सही हूं कि पुनरावर्ती कार्यान्वयन बड़ी मात्रा में कचरा उत्पन्न करता है क्योंकि प्रत्येक कॉल एक संशोधित सूची देता है जो संशोधित है जो एक नई सूची बनाता है और लौटाई गई सूची को कचरा के रूप में छोड़ देता है? क्या विनाशकारी परिचालनों का उपयोग करके इस पर कोई रास्ता है या इसका मतलब यह है कि कोई भी पुनरावर्ती कार्यान्वयन कचरा भारी होगा? – asm

+0

इन उत्तरों को चेक आउट करें: http://stackoverflow.com/questions/352203/generating-permutations-lazily –

+0

@Rainer अतिरिक्त जानकारी के लिए धन्यवाद! मैं एक एम्बेडेड प्रोग्रामर हूं और मुख्य रूप से सी का उपयोग करता हूं, इसलिए सीखना कि मुझे जीसी की भाषा का उपयोग करते समय चिंता करने की ज़रूरत है, मुझे कुछ काम करने की ज़रूरत है। @Nathan टिप के लिए धन्यवाद, यह वास्तव में दिलचस्प लग रहा है। – asm

1

आउटपुट के दिखने से, आप कीचड़-प्रतिलिपि देख रहे हैं, है ना?

"* अवरुद्ध-लिस्प * * बफर में बदलने का प्रयास करें, आप शायद देखेंगे कि एसबीसीएल एलडीबी (अंतर्निहित निम्न-स्तर डीबगर) में गिरा दिया गया है। सबसे अधिक संभावना है, आप कॉल-स्टैक को उड़ाने में कामयाब रहे हैं।

+0

अवरुद्ध-लिस्प वास्तव में एलडीबी में गिरा दिया गया है। ऐसा लगता है कि मेरे बारे में कुछ सीखने का समय है। – asm

2

अधिकांश प्लेटफार्मों पर एसबीसीएल पीढ़ी के कचरा कलेक्टर का उपयोग करता है, जिसका अर्थ यह है कि आवंटित स्मृति जो कुछ संग्रहों से अधिक जीवित रहती है, संग्रह के लिए शायद ही कभी माना जाएगा। दिए गए टेस्ट केस के लिए आपका एल्गोरिदम इतना कचरा उत्पन्न करता है कि यह जीसी को कई बार ट्रिगर करता है कि वास्तविक परिणाम, जो कि पूरे फ़ंक्शन रनटाइम से बचने के लिए स्पष्ट रूप से जीवित रहना है, यानी अंतिम पीढ़ी में ले जाया जाता है जो बहुत ही कम संग्रहित होता है या बिल्कुल नहीं। इसलिए, दूसरा रन, 32-बिट सिस्टम के लिए मानक सेटिंग्स पर, ढेर से बाहर चला जाएगा (512 एमबी, रनटाइम विकल्पों के साथ बढ़ाया जा सकता है)।

टेनेटेड डेटा कलेक्टर को (sb-ext:gc :full t) के साथ मैन्युअल रूप से ट्रिगर करके कचरा एकत्र किया जा सकता है। यह स्पष्ट रूप से कार्यान्वयन निर्भर है।

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