2011-01-12 17 views
8

में रीफ्रेश सीमाएं फिर से मैं एक ऐसे प्रश्न के लिए क्षमा चाहता हूं जो आप सभी के लिए आसान हो। सिल्वरलाइट में दृश्यों के पीछे क्या है, इसकी सीमित समझ है।डिस्पैचर टाइमर और यूआई सी # चांदी की रोशनी

मेरे पास एक चार्टिंग ऐप (Visiblox) है जो मैं रोलिंग स्कोप के रूप में उपयोग करता हूं जो प्रत्येक 20ms को अद्यतन करता है, एक बिंदु जोड़कर और हटा देता है। छद्म कोड में:

List<Point> datapoints= new List<Point>(); 
Series series = new Series(datapoints); 
void timer_tick(){ 
    datapoints.Add(new Point); 
    datapoints.RemoveAt(0); 
    // no need to refresh chart, it does refresh automatically 
} 

इस चार्टिंग टूल में 6 श्रृंखला चलाते समय, यह थोड़ा सुस्त दिखाना शुरू कर दिया। टिक को 10ms तक बदलना कोई फर्क नहीं पड़ता, चार्ट को उसी गति से अपडेट किया गया था, इसलिए ऐसा लगता है कि 20ms गति सीमा (UI या चार्ट?) है।

मैंने CompositionTarget.Rendering के साथ प्रयास किया और उसी परिणाम प्राप्त किए: नीचे 20ms गति में कोई अंतर नहीं था।

तब मैंने गलती से दोनों को गति और गति दोगुना कर दिया। तो मैंने कई धागे (2, 3, 4) और गति दोगुना, तीन गुना और चौगुनी के साथ परीक्षण किया। इसमें अभी तक कोई तालाब नहीं है, क्योंकि मुझे यह भी नहीं पता कि मुझे लॉक उत्पन्न करने के लिए किस प्रक्रिया की आवश्यकता है, लेकिन कोई डेटा भ्रष्टाचार नहीं मिला है और न ही स्मृति लीक है।

मेरे पास सवाल यह है कि क्यों 20ms पर एक आलसी चार्ट 10ms पर नहीं चल सकता है लेकिन बहुप्रचारित होने पर हास्यास्पद रूप से तेज़ है? क्या यूआई रीफ्रेश प्रक्रिया तेजी से चल रही है? क्या चार्ट गणना दोगुनी है? या क्या कोई सीमा है कि एक डिस्पैचर टिमर को कितनी तेजी से निष्पादित किया जा सकता है?

धन्यवाद!


संपादित करें: मैं एम्बेडेड कोडिंग की एक पृष्ठभूमि है, इसलिए जब मैं धागे और समय के बारे में सोच, मैं तुरंत हार्डवेयर में एक पिन टॉगल के बारे में सोच और प्रक्रिया लंबाई को मापने के लिए एक गुंजाइश ऊपर हुक। मैं सी # में धागे के लिए नया हूं और स्कॉप्स को हुक करने के लिए कोई पिन नहीं है। क्या ग्राफिक रूप से थ्रेड समय देखने का कोई तरीका है?

उत्तर

4

मुझे लगता है कि कुंजी यह जानना है कि सिल्वरलाइट डिफ़ॉल्ट रूप से 60fps की अधिकतम फ्रेम दर पर प्रस्तुत करता है (आपके मैक्सफ्रेमरेट संपत्ति के माध्यम से अनुकूलन योग्य)। इसका मतलब है कि DispatcherTimer टिक प्रति सेकेंड 60 गुना आग लग जाएगी। इसके अतिरिक्त, यूआई थ्रेड पर सभी प्रतिपादन कार्य भी होते हैं, इसलिए डिस्पैचर टिमर उस दर पर आग लगाता है जो चित्रकारी पिछले पोस्टर द्वारा इंगित किया गया है।

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

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

IDataSeries के पर्यवेक्षण चयन चयन से बंधे होने के बारे में आपके बिंदु के बारे में भी, आप आईडीटाइरीज इंटरफ़ेस को स्वयं लागू करने के लिए पूरी तरह से स्वतंत्र हैं, उदाहरण के लिए इसे सरल सूची के साथ समर्थन करके। बस जागरूक रहें कि स्पष्ट रूप से यदि आप ऐसा करते हैं तो डेटा बदलते समय चार्ट स्वचालित रूप से अपडेट नहीं होगा। आप Chart.Invalidate() या मैन्युअल रूप से सेट अक्ष श्रेणी को बदलकर चार्ट अपडेट को मजबूर कर सकते हैं।

+0

आप सही हैं। यह एक भ्रम है। धीमी गति से चार्ट की 'रोलिंग' आपकी आंखों से ट्रैक करना आसान है और आलसी आसानी से पता चला है, लेकिन एक समय में एक से अधिक बिंदुओं को अपडेट करना, आलसी देखना मुश्किल है। धन्यवाद! – PaulG

7

एक डिस्पैचर टिमर, जो यूआई थ्रेड पर अपनी टिक घटना को चलाता है, को कम-रिज़ॉल्यूशन या कम-सटीकता टाइमर माना जाता है क्योंकि इसका अंतराल प्रभावी रूप से "आखिरी टिक के बाद से x से अधिक टिक नहीं" का अर्थ है। यदि यूआई थ्रेड कुछ भी (प्रोसेसिंग इनपुट, चार्ट रीफ्रेशिंग इत्यादि) में व्यस्त है तो यह टाइमर की घटनाओं में देरी करेगा। इसके अलावा, बहुत कम अंतराल पर यूआई थ्रेड पर डिस्पैचर टिमर की टिकिंग का एक गुच्छा आपके आवेदन की प्रतिक्रिया को धीमा कर देगा क्योंकि टिक घटना को उठाया जा रहा है, तो एप्लिकेशन इनपुट का जवाब नहीं दे सकता है।

तो जैसा कि आपने नोट किया है, डेटा को अक्सर संसाधित करने के लिए, आपको पृष्ठभूमि थ्रेड पर जाना चाहिए। लेकिन चेतावनी हैं। तथ्य यह है कि आप वर्तमान में भ्रष्टाचार या अन्य बग का निरीक्षण नहीं कर रहे हैं, पूरी तरह से संयोग हो सकता है। यदि सूची पृष्ठभूमि थ्रेड पर एक ही समय में संशोधित की जा रही है, तो अग्रभूमि थ्रेड इसे पढ़ने की कोशिश कर रहा है, तो आप अंततः क्रैश हो जाएंगे (यदि आप भाग्यशाली हैं) या भ्रष्ट डेटा देखें।

आपके उदाहरण में, आपके पास एक टिप्पणी है जो कहती है "चार्ट रीफ्रेश करने की कोई आवश्यकता नहीं है, यह स्वचालित रूप से रीफ्रेश हो जाता है।" इससे मुझे आश्चर्य होता है कि चार्ट कैसे जानता है कि आपने datapoints संग्रह को बदल दिया है? List<T> संशोधित होने पर ईवेंट नहीं बढ़ाता है। यदि आप ObservableCollection<T> का उपयोग कर रहे थे तो मैं यह इंगित करता हूं कि प्रत्येक बार जब आप एक बिंदु को हटाते/जोड़ते हैं तो आप चार्ट को संभावित रूप से रीफ्रेश कर रहे हैं, जो चीजों को धीमा कर सकता है।

लेकिन यदि आप वास्तव में List<T> का उपयोग कर रहे हैं तो वहां कुछ और होना चाहिए (शायद एक और टाइमर?) जो चार्ट को रीफ्रेश कर रहा है। शायद चार्ट नियंत्रण में अंतर्निहित ऑटो-रीफ्रेश तंत्र है?

किसी भी स्थिति में, समस्या थोड़ा मुश्किल but not completely new है। ऐसे तरीके हैं जिन्हें आप पृष्ठभूमि थ्रेड पर संग्रह बनाए रख सकते हैं और यूआई थ्रेड से बांध सकते हैं। लेकिन तेज़ी से आपका यूआई रीफ्रेश हो जाता है, अधिक संभावना है कि आप पृष्ठभूमि थ्रेड के लिए लॉक जारी करने की प्रतीक्षा करेंगे।

इसे कम करने का एक तरीका List<T> के बजाय LinkedList<T> का उपयोग करना होगा। एक लिंक्डलिस्ट के अंत में जोड़ना ओ (1) है, इसलिए एक आइटम को हटा रहा है। जब आप शुरुआत से किसी आइटम को हटाते हैं तो List<T> को सब कुछ एक-दूसरे से नीचे ले जाने की आवश्यकता होती है। लिंक्डलिस्ट का उपयोग करके आप पृष्ठभूमि थ्रेड में इसे लॉक कर सकते हैं और आप लॉक रखने वाले समय को कम कर देंगे। यूआई थ्रेड पर आपको एक ही लॉक प्राप्त करने की आवश्यकता होगी और या तो सूची को सरणी में कॉपी करें या लॉक होने पर चार्ट रीफ्रेश करें।

एक और संभावित समाधान बैकग्राउंड थ्रेड पर बिंदुओं के "भाग" को बफर करना होगा और डिस्पैचर.बिनगिनवोक के साथ यूआई थ्रेड में बैच पोस्ट करना होगा, जहां आप सुरक्षित रूप से संग्रह को अपडेट कर सकते हैं।

+0

महान अंतर्दृष्टि के लिए धन्यवाद। आपकी कुछ चिंताओं का उत्तर देने के लिए, मैं बिल्कुल एक सूची <> का उपयोग नहीं कर रहा हूं, लेकिन एक संग्रह के कार्यान्वयन जिसमें INotifyCollection इसके साथ बदल गया है। चूंकि यह एक तृतीय पक्ष ऐप है, इसलिए इसके बारे में मैं इतना कुछ नहीं कर सकता। इस पर मेरा पहला दृष्टिकोण बिल्कुल वही था जैसा आपने सुझाव दिया था, मैं पृष्ठभूमि में बिटमैप प्रस्तुत कर रहा था, जबकि मैं अग्रभूमि में बिटमैप स्क्रॉल कर रहा था। लेकिन मेरे 'घर से बने' चार्टिंग टूल की समय की बाधाओं और गुणवत्ता के कारण, मैंने तीसरी पार्टी का चयन किया। तो लिंक्डलिस्ट और अन्य बाहर हैं, मुझे उनके विशिष्ट कार्यान्वयन का उपयोग करने की आवश्यकता है ... – PaulG

+0

(जारी रखा गया, वर्णों से बाहर चला गया) एक और बात, मुझे बस एहसास हुआ कि System.Windows.Threading यूआई के समान थ्रेड में चलने वाले धागे बनाता है, अन्यथा यूआई को अपडेट करना संभव नहीं होगा। सही? तो तथ्य यह है कि मैं सोच रहा था कि मैं multithreading गलत होना चाहिए। तब क्या हो रहा है? क्या Silverlight यूआई और डिस्पैच टाइमर के बीच साझा करने के लिए समय स्लाइस असाइन करता है और तथ्य यह है कि मैंने उनमें से कई को टाइमर कार्यों की प्राथमिकता बढ़ा दी है? – PaulG

+0

(जारी रखा गया III) यही कारण है कि मुझे लगता है कि मैं दुर्घटनाओं या बग को नहीं देख रहा हूं, क्योंकि मैं वास्तव में एकाधिक धागे नहीं चला रहा हूं बल्कि एक के बाद सिर्फ एक हूं।मेरा आवेदन एक अनुकरण उपकरण है जो प्रति टाइमर अवधि के हजारों मैट्रिक्स गणनाओं को संसाधित करता है, जिसके परिणामस्वरूप प्रति सेकंड लाखों गणनाएं होती हैं। मुझे अब तक दुर्घटनाग्रस्त होना चाहिए था। अगर मैं गलत हूं कृपया मुझे सही। ये सभी धारणाएं हैं। – PaulG

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