2009-06-19 29 views
10

मैं इस प्रकार रिकर्सिवली दृश्यों परिभाषित करना चाहते:रिकर्सिव अनुक्रम रिसाव स्मृति करें?

let rec startFrom x = 
    seq { 
     yield x; 
     yield! startFrom (x + 1) 
    } 

मुझे यकीन है कि नहीं कर रहा हूँ इस तरह पुनरावर्ती दृश्यों व्यवहार में प्रयोग किया जाना चाहिए। yield!पूंछ रिकर्सिव होने के लिए दिखाई देता है, लेकिन मुझे 100% निश्चित नहीं है क्योंकि इसे किसी अन्य आईनेमेरेबल के अंदर से बुलाया जा रहा है। मेरे दृष्टिकोण से, कोड प्रत्येक कॉल पर इसे बंद किए बिना IEnumerable का एक उदाहरण बनाता है, जो वास्तव में इस फ़ंक्शन को रिसाव मेमोरी भी बना देगा।

क्या यह कार्य रिसाव स्मृति होगा? उस मामले के लिए यह भी "पूंछ रिकर्सिव" है?

[जोड़ने के लिए संपादित करें]: मैं उत्तर के लिए एनप्रोफ के साथ घूम रहा हूं, लेकिन मुझे लगता है कि एसओ पर रिकर्सिव अनुक्रमों के कार्यान्वयन के संबंध में तकनीकी स्पष्टीकरण प्राप्त करना उपयोगी होगा।

+2

>> "दुर्भाग्य से, मेरे पास कोई प्रोफाइलर अनुभव नहीं है, इसलिए मैं कर सकता हूं अपने आप को जवाब नहीं मिला। " किसी तरह का मजाक? किसी को अनुभव कैसे मिलता है? – user79755

+2

रिकॉर्ड के लिए मैं अभी एनपीआरओफ़ देख रहा हूं, लेकिन आशा है कि एसओ पर एक तेज उत्तर और तकनीकी स्पष्टीकरण प्राप्त हो रहा है। – Juliet

उत्तर

7

मैं काम में हूँ अब तो मैं Beta1 की तुलना में थोड़ा नए बिट्स को देख रही है, लेकिन रिलीज मोड में मेरी बॉक्स पर और फिर नेट परावर्तक साथ संकलित कोड को देखते हुए ऐसा लगता है इन दो

let rec startFromA x =  
    seq {   
     yield x  
     yield! startFromA (x + 1)  
    } 

let startFromB x =  
    let z = ref x 
    seq {   
     while true do 
      yield !z 
      incr z 
    } 
कि

'रिलीज' मोड में संकलित होने पर लगभग समान एमएसआईएल कोड उत्पन्न करता है। और वे इस सी # कोड के रूप में लगभग उसी गति पर चलाएँ:

public class CSharpExample 
{ 
    public static IEnumerable<int> StartFrom(int x) 
    { 
     while (true) 
     { 
      yield return x; 
      x++; 
     } 
    } 
} 

(जैसे मैं अपने बॉक्स पर सभी तीन संस्करणों भाग गया और दस लाखवाँ परिणाम मुद्रित, और प्रत्येक संस्करण 1.3s के बारे में ले लिया +/- 1s)। (मैंने कोई मेमोरी प्रोफाइलिंग नहीं की है; यह संभव है कि मुझे कुछ महत्वपूर्ण याद आ रही है।)

संक्षेप में, जब तक आप कोई समस्या मापते और देखते हैं, तब तक मैं इस तरह के मुद्दों के बारे में बहुत ज्यादा सोच नहीं पड़ेगा।

संपादित

मुझे लगता है मैं वास्तव में इस सवाल का जवाब नहीं था ... मुझे लगता है कि कम जवाब है, "नहीं, यह लीक नहीं करता है"।(एक विशेष भावना जिसमें सभी 'अनंत' एक कैश्ड समर्थन की दुकान के साथ IEnumerables() 'रिसाव' (आप 'रिसाव') कैसे परिभाषित के आधार पर नहीं है, IEnumerable का एक दिलचस्प चर्चा के लिए

Avoiding stack overflow (with F# infinite sequences of sequences)

देखना (उर्फ 'seq') LazyList बनाम और कैसे उपभोक्ता उत्सुकता से LazyLists को एक निश्चित प्रकार के 'रिसाव' को रोकने के लिए पुराने परिणामों को भूलने के लिए उत्सुकता से उपभोग कर सकता है।)

+1

धन्यवाद, ब्रायन :) और बाकी F # टीम के साथ भी kudos :) – Juliet

-1

.NET अनुप्रयोग इस तरह से स्मृति को "रिसाव" नहीं करते हैं। यहां तक ​​कि यदि आप कई ऑब्जेक्ट्स बना रहे हैं, तो कचरा संग्रह किसी ऑब्जेक्ट को मुक्त कर देगा, जिसमें एप्लिकेशन के लिए कोई जड़ नहीं है।

.NET में मेमोरी लीक आमतौर पर अप्रबंधित संसाधनों के रूप में आती हैं जिनका उपयोग आप अपने एप्लिकेशन (डेटाबेस कनेक्शन, मेमोरी स्ट्रीम इत्यादि) में कर रहे हैं। इस तरह के उदाहरण जिसमें आप कई ऑब्जेक्ट्स बनाते हैं और फिर उन्हें त्यागते हैं उन्हें स्मृति रिसाव नहीं माना जाता है क्योंकि कचरा कलेक्टर स्मृति को मुक्त करने में सक्षम होता है।

+1

कचरा संग्रह इस बात को लेकर कोई गारंटी नहीं देता है कि यह इन वस्तुओं को एकत्र करने के लिए कब जा रहा है। तो नहीं, यह स्मृति रिसाव अभ्यास नहीं है लेकिन यह एक अच्छी स्मृति अर्थव्यवस्था अभ्यास नहीं है। – marr75

+0

@ marr75 - अच्छा बिंदु और अच्छा भेद! –

+1

यह भी संभव है कि जेनरेट किए गए आईनेमेरेबल को संरचित किया जा सके ताकि पहले तत्वों को अब कचरा संग्रह के लिए योग्य न हो, जब भी उनकी आवश्यकता न हो, जिसे मैं एक प्रकार की रिसाव पर विचार करूंगा। – kvb

-1

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

+2

यह इस बात पर निर्भर करता है कि फ़ंक्शन पूंछ-रिकर्सन का उपयोग करता है या नहीं। तुलना के लिए, समकक्ष सी # कोड लगभग 15000 पूर्णांक के बाद एक स्टैक ओवरफ्लो एक्सेप्शन फेंक देगा: स्थैतिक आईनेमेरेबल स्टार्टफ्रॉम (int x) {उपज वापसी x; foreach (शुरुआत में int y (x + 1)) उपज वापसी वाई; } – Juliet

+1

परिशिष्ट: एक त्वरित परीक्षण के बाद, ऐसा लगता है कि एफ # कोड * है * पूंछ रिकर्सिव। अच्छी खबर है :) – Juliet

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