2014-10-02 5 views
6

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

public class FeedMockUp 
    { 
     private readonly IScheduler observerScheduler; 
     private readonly Random rnd = new Random((int)DateTime.Now.Ticks); 

     private readonly Subject<double> sourceObservable; 
     private readonly IObservable<double> testedObservable; 

     public FeedMockUp(IScheduler observerScheduler) 
     { 
      this.observerScheduler = observerScheduler; 
      sourceObservable = new Subject<double>(); 

      testedObservable = 
       Observable.Create<double>(x => 
       { 
        var underlyingSourceDisposable = 
         sourceObservable 
          .Subscribe(_ => x.OnNext(rnd.NextDouble())); 
        return underlyingSourceDisposable; 
       }); 
     } 

     public IDisposable SubscribeToUnderlyingFeed(int numberOfSubscribers) 
     { 
      int counter = 0; 
      var disposable = new CompositeDisposable(); 

      for (int i = 0; i < numberOfSubscribers; i++) 
      { 
       disposable.Add(testedObservable 
        .ObserveOn(observerScheduler) 
        .Subscribe(_ => Interlocked.Increment(ref counter))); 
      } 

      return disposable; 
     } 

     public void PushNewFeed() 
     { 
      sourceObservable.OnNext(rnd.NextDouble()); 
     } 
    }  

जब मैं चारों ओर खेल रहा था अवलोकन अद्यतनों के थ्रूपुट को बेहतर बनाने के लिए शेड्यूलर के साथ मैंने देखा है कि 1000 पर्यवेक्षकों के साथ 100 डेटा फीड वाले अनुप्रयोग की स्मृति खपत काफी स्थिर थी, 1000 पर्यवेक्षकों के लिए यह ~ 100 एमबी और नए पर्यवेक्षकों को जोड़ने के दौरान रैखिक रूप से बढ़ रहा था मिश्रित होना।

हालांकि जब मैं TaskPoolScheduler का उपयोग कर की कोशिश की है, 86 प्रक्रिया पर मैं OutOfMemoryException अपवाद हो रही है और 64 प्रक्रिया स्मृति की खपत पर शुरू कर दिया है विस्फोट हो गया, या कहें, सिर्फ 500 पर्यवेक्षकों के लिए 2 जीबी 1 जीबी से कहीं भी लेकर और लगभग बढ़ रही है काफी अनिश्चित हो गया मिश्रण में नए पर्यवेक्षकों के साथ तेजी से।

यहां कोड है जिसका उपयोग मैं परीक्षण के लिए कर रहा हूं। क्या आप देख सकते हैं कि इसमें क्या गलत है? प्रदर्शन में इतना अंतर क्यों? अनुमान लगाते हुए, यहां कुछ आंतरिक प्रतिलिपि/कतार शामिल है, लेकिन यह मेरा अनुमान है। आदर्श रूप में मैं ObserveOnTaskPoolScheduler साथ अनिवार्य रूप से प्रत्येक पर्यवेक्षक के लिए एक LongRunning कार्य बनाने के लिए जा रहा है का उपयोग करके पता लगाएं कि RX कोड आधार के लिए डाइविंग के बिना यहाँ क्या हो रहा है चाहता हूँ ...

private static void Main(string[] args) 
    { 
     const int displayItemCount = 100; 
     const int callbackCount = 500; 

     //var rtScheduler = new EventLoopScheduler(); 
     var rtScheduler = TaskPoolScheduler.Default; 
     var rtFeeds = new List<FeedMockUp>(); 
     for (int i = 0; i < displayItemCount; i++) 
     { 
      var mockFeed = new FeedMockUp(rtScheduler); 
      mockFeed.SubscribeToUnderlyingFeed(callbackCount); 
      rtFeeds.Add(mockFeed); 
     } 
     foreach (var rtFeedMockUp in rtFeeds) 
     { 
      rtFeedMockUp.PushNewFeed(); 
     } 
     Console.WriteLine("Memory used for feed {0} mockups with {1} observers/callbacks. Memory {2} Mb", 
      displayItemCount, callbackCount, Environment.WorkingSet/(1024 * 1024)); 
Console.ReadKey(); 

} 

उत्तर

9

और डिफ़ॉल्ट TaskSchedulercreating a Thread for each LongRunning tasks समाप्त होता है।

और प्रत्येक थ्रेड अपने ढेर के लिए लगभग 1 एमबी आरक्षित करता है।

तो, TaskPoolScheduler का उपयोग कर 500 पर्यवेक्षक कम से कम 500 एमबी आरक्षित करेंगे। आप देख सकते हैं कि यह कहां जा रहा है ...

दूसरी ओर, EventLoopScheduler, एक ही धागे पर चलता है। इसलिए इस शेड्यूलर के साथ ObserveOn का उपयोग करके प्रभावी रूप से शेड्यूलर की कार्य कतार में एक प्रविष्टि जोड़ती है। यह प्रविष्टि थ्रेड की 1 एमबी लागत से बहुत छोटी है।

तो, EventLoopScheduler इस परिदृश्य के लिए बहुत अधिक मेमोरी कुशल है, लेकिन यह पर्यवेक्षकों को क्रमशः सूचित करता है और अगर पर्यवेक्षकों के बहुत सारे हैं और स्रोत उच्च आवृत्ति पर उत्पादन कर रहा है, तो आप एक बफर जमा करना शुरू कर देंगे असंतोष घटनाओं के।

TaskPoolScheduler कम स्मृति कुशल है लेकिन पर्यवेक्षकों को समवर्ती रूप से सूचित करेगा और इस प्रकार आपकी मशीन पर सभी कोरों का उपयोग करके EventLoopScheduler की तुलना में उच्च आवृत्ति घटनाओं को संभावित रूप से संभाल सकता है।

+1

'टास्कलोपशेड्यूलर'? एक टाइपो की तरह लगता है ... –

+1

आप प्रति कोर 'EventLoopScheduler' भी बना सकते हैं और प्रवेश बिंदु पर लोड बैलेंसर लागू कर सकते हैं; उदाहरण के लिए, राउंड-रॉबिन शेड्यूलर चयन। इसे अपने 'आईएसड्यूलरर' कार्यान्वयन के अंदर लपेटा जा सकता है ताकि आपको केवल एक ही रेफरी पारित करने की आवश्यकता हो। –

+1

मेमोरी देखने में काफी मनोरंजक लग रहा है जब थ्रेड पूल इसकी धागा गिनती शुरू कर देता है! http://imgur.com/NGnDOH0 फिक्स्ड कि टाइपो बीटीडब्ल्यू डेव। साथ ही, मैंने उस दृष्टिकोण का उपयोग किया है जिसे आपने अतीत में सफलतापूर्वक सुझाव दिया था। –

5

शायद आप TaskPoolScheduler.Default.DisableOptimizations(typeof(ISchedulerLongRunning)) का उपयोग करना चाहते हैं। EventLoopScheduler एक अच्छा विकल्प है यदि आप समांतरता को खोने पर ध्यान नहीं देते हैं।

यह विकल्प बेहतर है यदि आप अभी भी समानांतर में काम निष्पादित करना चाहते हैं लेकिन थ्रेड पूल थ्रेड का उपयोग करना चाहते हैं।

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