2011-04-12 18 views
5

अनुप्रयोगों को डिजाइन करने के लिए आम दृष्टिकोण क्या है, जो C# (LINQ, IEnumerable, IQueryable, ...) में आलसी मूल्यांकन पर दृढ़ता से भरोसा करते हैं?सी # आलस्य प्रश्न

अभी मैं आमतौर पर हर प्रश्न के रूप में संभव के रूप में आलसी बनाने के लिए, yield return और LINQ प्रश्नों का उपयोग कर प्रयास करते हैं, लेकिन क्रम में यह आम तौर पर, "बहुत आलसी" व्यवहार करने के लिए ले जा सकता है जब प्रत्येक जिज्ञासा जाहिर है, जिसके परिणामस्वरूप शुरुआत है इसे से builts हो जाता है गंभीर दृश्य प्रदर्शन गिरावट में।

मैं आमतौर पर डेटा का कैश करने के लिए ToList() प्रोजेक्शन ऑपरेटरों को डालने का मतलब रखता हूं, लेकिन मुझे संदेह है कि यह दृष्टिकोण गलत हो सकता है।

इस तरह के अनुप्रयोगों को बहुत शुरुआत से डिजाइन करने के लिए उचित/सामान्य तरीके क्या हैं?

उत्तर

4

मुझे प्रत्येक आईनेमरेबल को तीन श्रेणियों में से एक में वर्गीकृत करने के लिए उपयोगी लगता है।

  1. तेज़ वाले - उदा। सूचियां और सरणी
  2. धीमे वाले - उदा।डेटाबेस क्वेरीज या भारी गणना
  3. गैर-निर्धारिती वाले - उदा। list.Select (x => नई {...})

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

2

कुछ यादृच्छिक विचार - प्रश्न के रूप में हल्के ढंग से परिभाषित किया गया है:

  • लेज़ी अच्छा है केवल जब परिणाम इसलिए इस्तेमाल नहीं किया जा सकता है लोड केवल जब जरूरत। अधिकांश परिचालनों को, हालांकि, डेटा को लोड करने की आवश्यकता होगी ताकि उस अवधि में आलस्य अच्छा न हो।
  • आलस्य मुश्किल बग का कारण बन सकता है। हम यह सब ORMs में डेटा संदर्भों के साथ देखा है
  • लेज़ी अच्छा है जब यह मैं आप डेटा की एक निश्चित अनुक्रम की जरूरत कैश हो जाने की, एकत्रीकरण ऑपरेटरों में से एक (ToList, ToArray फोन MEF
1

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

अपने डेटा के चारों ओर अपना कोड बनाएं। कौन सा डेटा अस्थिर है और हर बार ताजा खींचा जाना चाहिए? आलसी मूल्यांकन का प्रयोग करें और कैश न करें। कौन सा डेटा अपेक्षाकृत स्थिर है और केवल एक बार खींचने की जरूरत है? स्मृति में डेटा कैश करें ताकि आप इसे अनावश्यक रूप से खींच न सकें।

2

बहुत व्यापक प्रश्न और दुर्भाग्य से आप इसे बहुत कुछ सुनेंगे: यह निर्भर करता है। आलसी लोडिंग तब तक बढ़िया है जब तक यह नहीं है।

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

लेकिन शायद ही कभी यह आपके कॉलर्स को इस तरह से जानना समझ में आता है। यही है, अगर आप किसी रिपॉजिटरी या किसी चीज़ से IENumerables प्राप्त कर रहे हैं, तो रिपोजिटरी को अपना काम करने देना सबसे अच्छा है। यह इसे आंतरिक रूप से एक सूची के रूप में कैश कर सकता है या यह हर बार इसे बना सकता है। अपने कॉल करने के बहुत चालाक प्राप्त करने की कोशिश अगर वे, डेटा में परिवर्तन छूट आदि हो सकता है

2

मैं डीटीओ

public IList<UserDTO> GetUsers() 
{ 
    using (var db = new DbContext()) 
    { 
    return (from u in db.tblUsers 
      select new UserDTO() 
      { 
       Name = u.Name 
      }).ToList(); 
    } 
} 

लौटने आप ऊपर के उदाहरण में से पहले अपने दाल में एक ToList का सुझाव देते हैं जाएगा है DbContext गुंजाइश समाप्त होने से पहले एक ToList() करने के लिए।

+1

पवित्र मोली! मेरे पास एक मीट्रिक टन कोड है जो लगभग समान दिखता है! :) –

0

.ToList() के साथ सभी आइटम को निष्पादित निष्पादन और कैशिंग केवल एकमात्र विकल्प नहीं हैं। तीसरा विकल्प आइटम को कैश करना है जबकि आप आलसी सूची का उपयोग करके पुनरावृत्त कर रहे हैं।

निष्पादन अभी भी स्थगित है लेकिन सभी आइटम केवल एक बार प्राप्त किए जाते हैं। कैसे यह काम का एक उदाहरण:

public class LazyListTest 
{ 
    private int _count = 0; 

    public void Test() 
    { 
     var numbers = Enumerable.Range(1, 40); 
     var numbersQuery = numbers.Select(GetElement).ToLazyList(); // Cache lazy 
     var total = numbersQuery.Take(3) 
      .Concat(numbersQuery.Take(10)) 
      .Concat(numbersQuery.Take(3)) 
      .Sum(); 
     Console.WriteLine(_count); 
    } 

    private int GetElement(int value) 
    { 
     _count++; 
     // Some slow stuff here... 
     return value * 100; 
    } 
} 

आप टेस्ट() विधि चलाते हैं, _count केवल 10 कैशिंग यह 16 और के साथ हो सकता है बिना है। ToList() यह 40 होगा!

implementation of LazyList can be found here का एक उदाहरण।

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