16

मैं हास्केल और एफपी पर ठोकर खाई और संभावनाओं से डर गया। और मेरे अंदर घिरे पुराने गणित को वास्तविक उपयोगी उद्देश्यों के लिए बेवकूफ कोड लिखने में कोई परेशानी नहीं थी। हालांकि सभी पठन के बावजूद मुझे अभी भी मुश्किल समय समझ रहा है कि कुछ आश्चर्यजनक प्रदर्शन बाधाओं को कैसे नहीं मारा जाए।हास्केल मेमोरी आवंटन व्यवहार को समझना मुश्किल है

इसलिए मैं निष्पक्ष कार्यान्वयन के साथ कोड के बहुत छोटे टुकड़े लिखता हूं और फिर प्रदर्शन को प्रतिक्रिया देने के तरीके में थोड़ा बदलाव करने की कोशिश करता हूं। और यहां एक उदाहरण है जो मैं वास्तव में समझने के लिए नहीं मिल सकता ... मैंने इस फ़ंक्शन को लिखा है जो Josephus problem, पर एक उद्देश्य सूची कार्यान्वयन के साथ पर समाधान ढूंढता है।

m = 3 
n = 3000 
main = putStr $ "Soldier #" ++ (show $ whosLeft [1..n]) ++ " survived...\n" 

whosLeft [lucky] = lucky 
whosLeft soldiers = whosLeft $ take (length soldiers -1) $ drop m $ cycle soldiers 

उत्तरार्द्ध आरटीएस के अनुसार 63% की उत्पादकता के साथ 1 9 0 एमएस में चलता है।

तब पहली चीज़ जो मैं कोशिश करना चाहता था वह था (लंबाई सैनिक -1) को हटाने और इसे कम करने वाले पूर्णांक के साथ प्रतिस्थापित करना था।

चलने का समय 900 एमएस तक और उत्पादकता 16% तक गिर गया, और ऊपर दिए गए सरल कोड की तुलना में 47 गुना अधिक स्मृति का उपयोग करता है! इसलिए मैंने सख्त मूल्यांकन जोड़ा, इंट टाइप को मजबूर किया, वैश्विक चर और दूसरों को हटाने जैसी चीजों की कोशिश की, फिर भी इसका लाभ उठाने के लिए नहीं। और मैं बस इस मंदी को समझ नहीं सकता।

m = 3::Int 
n = 3000::Int 
main = putStr $ "Soldier #" ++ (show $ whosLeft n [1..n]) ++ " survived...\n" 

whosLeft 1 [lucky] = lucky 
whosLeft n' soldiers = n' `seq` left `seq` whosLeft (n'-1) left 
       where left = take (n'-1) $ drop m $ cycle soldiers 

मैंने प्रदर्शन संबंधी लेख और पोस्ट के माध्यम से छेड़छाड़ की है, लेकिन मुझे इस बारे में कोई संकेत नहीं दिख रहा है। अभी भी एक हास्केल नोब होने के नाते मुझे कुछ बड़ा याद आना चाहिए ... यह कैसे जोड़ा जा सकता है पैरामीटर (पूर्व-चबाने वाला गणना ...) गति को इतना कम करता है?

पुनश्च: मैं जानता हूँ कि, अगर जोसेफस वास्तव में 3000 सैनिकों के साथ किया गया था, वे आत्महत्या करने की जरूरत नहीं है | ...

+1

सीक एन 'की कोई ज़रूरत नहीं है, whosLeft पहले से ही सख्त है'। लेकिन आपको अनुकूलन के साथ संकलित करना चाहिए। – augustss

उत्तर

9

पहला समाधान इसकी लंबाई लेने के द्वारा सैनिकों सूची के पूरे रीढ़ बाध्य करती है। दूसरा समाधान केवल सैनिकों की सूची (seq का उपयोग करके) हेड का उपयोग करता है। leftseq एस के बीच length left के बीच बदलें और आपको अपना प्रदर्शन वापस मिल जाएगा।

+0

कमाल। इसलिए मैंने पूरी तरह से इस बिंदु को याद किया था, और यह सब के बाद आसान था: डी बहुत बहुत धन्यवाद। यह जानने के लिए एक दिलचस्प चाल है। –

+0

क्या यह ऐसी चीज है जो [deepseq] (http://hackage.haskell.org/package/deepseq) पैकेज के लिए अच्छा है? –

+1

@ एंटल: मैं गहरे सेक का उपयोग नापसंद करता हूं, क्योंकि यह एक ब्लंट वाद्य यंत्र है। इस मामले में उदाहरण के लिए, आपको केवल सूची की रीढ़ की हड्डी को मजबूर करने की आवश्यकता है। दीपसेक मूल्यों को भी मजबूर करता है। यह अपेक्षाकृत सस्ता है, क्योंकि वे अनिवार्य रूप से पहले से ही मजबूर हैं, लेकिन एक मामूली लागत है, और यदि आप इसे सूची की लंबाई और रिकर्सिव कॉल की संख्या से गुणा करते हैं तो यह बढ़ जाता है। अगर आप जल्दबाजी में हैं तो दीपसेक ठीक है, लेकिन मुझे लगता है कि आलसीपन और सख्तता को इष्टतम तरीके से मिश्रित करने के लिए बेहतर होता है, जिससे यह अंधाधुंध के बजाय परिचालन रूप से समझ में आता है। – sclv

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