2012-02-08 11 views
6

मैं इस डाटा प्रवाह, मोटे तौर पर है सम्मिलित करने कोड लिखने:जावा + घुमाओ: परिवर्तन की घटनाओं

DataGenerator -> DataFormatter -> UI 

DataGenerator कुछ है कि तेजी से डेटा उत्पन्न करता है; डेटाफॉर्मेटर ऐसा कुछ है जो इसे प्रदर्शन उद्देश्यों के लिए प्रारूपित करता है; और यूआई स्विंग तत्वों का सिर्फ एक गुच्छा है।

मैं इस तरह मेरी DataGenerator कुछ करना चाहते हैं:

class DataGenerator 
{ 
    final private PropertyChangeSupport pcs; 
    ... 
    public void addPropertyChangeListener(PropertyChangeListener pcl) { 
    this.pcs.addPropertyChangeListener(pcl); 
    } 
    public void removePropertyChangeListener(PropertyChangeListener pcl) { 
    this.pcs.removePropertyChangeListener(pcl); 
    } 
} 

और जब भी मेरे डेटा जनरेटर नए डेटा है सिर्फ this.pcs.firePropertyChange(...) कहते हैं; तो मैं सिर्फ dataGenerator.addPropertyListener(listener) कर सकता हूं जहां listener डेटाफॉर्मेटर में और फिर यूआई में परिवर्तन को धक्का देने के लिए ज़िम्मेदार है।

इस दृष्टिकोण के साथ समस्या यह है कि हजारों डेटा जनरेटर प्रति सेकंड बदलते हैं (मेरी स्थिति के आधार पर प्रति सेकंड 10,000 और 60,000 के बीच), और यूआई के लिए इसे स्वरूपित करने की कम्प्यूटेशनल लागत पर्याप्त है कि यह एक मेरे सीपीयू पर अनावश्यक भार; वास्तव में मुझे प्रति सेकंड लगभग 10-20 परिवर्तनों पर नजर रखने की परवाह है।

क्या समान दृष्टिकोण का उपयोग करने का कोई तरीका है, लेकिन डेटाफॉर्मेटर तक पहुंचने से पहले परिवर्तन घटनाओं को सहारा दें? अगर मुझे एक ही विषय पर कई अपडेट इवेंट प्राप्त होते हैं, तो मुझे केवल नवीनतम प्रदर्शित करने की परवाह है, और पिछले सभी को छोड़ सकता है।

+0

सिस्टम के साथ एक लंबा मूल्य बनाए रखने के बारे में कैसे करें। अंतिम यूआई- अपडेट करें, और संपत्ति-परिवर्तन घटनाओं को अनदेखा करें यदि वे अद्यतन के बाद एन एनएस लेते हैं? – aioobe

+0

मैंने सोचा कि (हेक, 'System.currentTimeMillis()' काम करेगा - मुझे लगता है कि चीजें मानव धारणा के सापेक्ष त्वरित हैं), लेकिन एक समस्या है। आइए मान लें कि दृश्य दृश्य के बाद आपके पास 100 माइक्रोसॉन्ड परिवर्तन ईवेंट है, इसलिए डेटाफॉर्मेटर/UI परिवर्तन को अनदेखा करता है। अब किसी कारण से DataGenerator अद्यतनों को बंद करना बंद कर देता है (यह लगातार प्रति सेकंड 10-60K ईवेंट नहीं है)। ओह, आपने हालिया परिवर्तन को याद किया है। यह बुरी बात है। –

उत्तर

4

दो विचारों:

  • सकल PropertyChangeEvent रों। PropertyChangeSupport बढ़ाएं, public void firePropertyChange(PropertyChangeEvent evt) ओवरराइट करें, केवल तभी आग लगें जब अंतिम ईवेंट 50ms से अधिक (या जो भी समय उचित लगता है) निकाल दिया गया हो। (वास्तव में आपको विधि या कम से कम उस व्यक्ति को अपने परिदृश्य में PropertyChangeEvent के निर्माण को रोकने के लिए ओवरराइट करना चाहिए।)
  • पूरे ईवेंट आधारित संपर्क को छोड़ दें। प्रति सेकंड 60,000 घटनाएं काफी अधिक संख्या है। इस स्थिति में मैं मतदान करूंगा। यह एमवीपी में एक वैचारिक परिवर्तन है जहां प्रस्तुतकर्ता जानता है कि यह सक्रिय राज्य में है और क्या मतदान करना चाहिए। इस दृष्टिकोण के साथ आप हजारों बेकार घटनाएं उत्पन्न नहीं करते हैं; आप प्रति सेकंड उच्चतम संभव फ्रेम भी प्रस्तुत कर सकते हैं, इससे कोई फर्क नहीं पड़ता कि कितना डेटा है। या आप प्रस्तुतकर्ता को एक निश्चित दर पर सेट कर सकते हैं, इसे किसी निश्चित समय के लिए रीफ्रेश के बीच सोएं, या इसे अन्य परिस्थितियों (जैसे CPU लोड) के अनुकूल बनाएं।

मैं दूसरे दृष्टिकोण के लिए प्रवृत्त होगा।

+0

ठीक है। आपके दूसरे दृष्टिकोण के लिए, क्या मतदान का उपयोग करने का कोई तरीका है (मैं आसानी से परमाणु बूलियन का उपयोग करके किसी प्रकार का "बदला" ध्वज रख सकता हूं) लेकिन फिर भी दोनों पक्षों के बीच एक decoupling रखना? मैं नहीं चाहता कि मेरे डेटा जेनरेटर को अपने डाउनस्ट्रीम क्लाइंट के बारे में जानना पड़े; इसके अलावा, मेरी समस्या का विवरण थोड़ा सा सरल था: हकीकत में प्रति सेकंड 10-60K परिवर्तनों के साथ 256 डेटा जेनरेटर हैं। (ज्यादातर समय केवल कुछ ही सक्रिय होते हैं, लेकिन मैं भविष्यवाणी नहीं कर सकता कि कौन से किसी भी समय दिए गए हैं। यह एक लंबी कहानी है।) संपत्ति-परिवर्तन दृष्टिकोण अच्छा है कि मुझे जरूरी अधिसूचना मिलती है। –

+0

लेकिन आपको अभी भी शुरुआत में कुछ उदाहरणों पर पंजीकरण करना होगा। क्या इससे कोई फर्क पड़ता है कि क्या आप मतदान के संदर्भ को संदर्भित कर रहे हैं या 'context.addPropertyChangeListener (this)' को कॉल कर रहे हैं? मैं मानता हूं कि यह सक्रिय, decoupled मॉडल होने के लिए एक क्लीनर अवधारणा हो सकता है - लेकिन इस डेटा राशि के साथ नहीं (और एमवीपी पैटर्न ऐसे कारणों से जिम्मेदारियों को बदलता है)। मैं एक 'एग्रीगेटर' लिखूंगा जो आपके 'डेटा जेनरेटर' को जानता है, डेटा एकत्र करता है और प्रस्तुतकर्ता द्वारा मतदान किया जा सकता है। असल में यह 'एग्रीगेटर' प्रति सेकंड 20 घटनाएं भी भेज सकता है। मैं 60,000 घटना प्रक्रियाओं को कुशल या उपयोगी के रूप में नहीं देखता हूं। –

+0

आह - मुझे एग्रीगेटर विचार पसंद है, धन्यवाद! –

0

आप अपने खुद के छोटे बदलाव श्रोता एक अवरुद्ध झंडा और एक टाइमर है कि लिखते हैं, आप कर सकते हैं:

syncronized onChangeRequest() { 
    if (flag) { 
     flag = false; 
     startTimer(); 
    } 
} 

timerEvent() { 
    notify all your listeners; 
} 

मेरा मानना ​​है कि वहाँ वास्तव में एक उत्कृष्ट अवरुद्ध संगामिति झंडा कि इस्तेमाल किया जा सकता है, लेकिन मैं के लिए नहीं कर सकते हैं मुझे याद है कि इसे क्या कहा जाता है!

1

आप इस्तेमाल कर सकते हैं आकार 1 है, जिसमें आप offer() समारोह के साथ अपने डेटा धक्का होगा की एक ArrayBlockingQueue (अर्थ है कि यदि कतार भर गई है, यह कुछ भी नहीं है)

फिर एक ScheduledThreadPoolExecutor जो समय समय पर चुनाव कतार बना।

इस तरह आप पीढ़ी और प्रदर्शन के बीच युग्मन को खो देते हैं।

जेनरेटर -> पंक्ति -> स्वरूपण/प्रदर्शन

+0

लेकिन मुझे कतार नहीं चाहिए; मैं घटनाओं को जोड़ना चाहता हूं।यदि डेटा जनरेटर कहता है "मेरा मान नीला है!" और फिर बाद में "मेरा मूल्य लाल है!" और फिर बाद में "मेरा मूल्य बैंगनी है!" मुझे पहले दो की परवाह नहीं है, मुझे बस नवीनतम की परवाह है। –

3

यह अपने DataGenerator EDT-धागे पर गैर जीयूआई बहुत काम कर रही है जैसा लगता है। मैं अनुशंसा करता हूं कि आपके DataGeneratorSwingWorker का विस्तार करें और इसके द्वारा पृष्ठभूमि थ्रेड में काम कर रहे हैं, doInBackground में लागू किया गया है। स्विंगवर्कर publish जीयूआई के मध्यवर्ती परिणाम हो सकता है, जबकि आपके पास process विधि है जो ईडीटी पर अंतिम कुछ प्रकाशित भाग प्राप्त करती है और आपके जीयूआई को अपडेट करती है।

SwingWorkers process विधि तो यह हर प्रकाशित मध्यवर्ती परिणाम के लिए एक बार नहीं चलेंगे, coalescepublished हिस्सा है।

यदि आप अंतिम परिणाम EDT पर आप इस कोड का उपयोग कर सकते हैं, जो केवल सूची में अंतिम हिस्सा परवाह की ही देखभाल: के बारे में अधिक SwingWorker: Tasks that Have Interim Results

@Override 
protected void process(List<Integer> chunks) { 

    // get the *last* chunk, skip the others 
    doSomethingWith(chunks.get(chunks.size() - 1)); 
} 

पढ़ें।

+0

डेटा जनरेटर ईडीटी थ्रेड में नहीं है और विभिन्न कारणों से निष्पादक सेवा द्वारा प्रबंधित किसी अन्य थ्रेड में होता है। –

+0

@ जेसनएस: मैं देखता हूं। लेकिन 'स्विंगवॉर्कर' को 'एक्जिक्यूटर्स सर्विस' पर भी चलाया जा सकता है, 'स्विंगवर्कर' दस्तावेज देखें: 'क्योंकि स्विंगवर्कर रननेबल लागू करता है, इसलिए स्विंगवर्कर निष्पादन के लिए एक निष्पादक को सबमिट किया जा सकता है।' – Jonas

+0

@ जेसनएस: मेरे पास एक पूर्ण उदाहरण है स्विंगवर्कर से नवीनतम इंटरमीडिएट परिणाम का उपयोग कैसे करें [स्विंगवर्कर थ्रेड को रोकें/रद्द करें?] (http://stackoverflow.com/a/9182043/213269) – Jonas

1

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

Timer timer = new Timer(100, new ActionListener(){//update the UI in this listener}; 

public void propertyChange(PropertyChangeEvent event){ 
if (timer.isRunning()){ 
    timer.restart(); 
} else { 
    timer.start(); 
} 
} 

यह काम करेगा जब तक कि आपके डेटा जनरेटर डेटा उत्पन्न करने पर रहता है पूरे समय, या यदि आप मध्यवर्ती अद्यतन भी चाहते हैं। उस स्थिति में आप केवल timer.restart() कॉल को हटा सकते हैं, या इस थ्रेड में अन्य किसी भी सुझाव का चयन कर सकते हैं (मतदान तंत्र, या SwingWorker)

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