2012-12-12 22 views
15

एक सी # (.NET 4.0) अनुप्रयोग में, मैं समेकित एक्सटेंशन (2.0.20823.0) का उपयोग समेकित मूल्यों में समूहबद्ध करने के लिए समय सीमाएं उत्पन्न करने के लिए करता हूं। परिणामस्वरूप डेटाबेस में प्रश्नों को सरल बनाने के लिए, इन सीमाओं को पूर्ण घंटों (या नीचे दिए गए उदाहरण में सेकंड) पर गठबंधन करने की आवश्यकता है।अवलोकन करने योग्य। टिमर(): टाइमर बहाव से कैसे बचें?

Observable.Timer() का उपयोग करना:

var time = DefaultScheduler.Instance; 

var start = new DateTimeOffset(time.Now.DateTime, time.Now.Offset); 

var span = TimeSpan.FromSeconds(1); 

start -= TimeSpan.FromTicks(start.Ticks % 10000000); 
start += span; 

var boundary = Observable.Timer(start, span, time); 

boundary.Select(i => start + TimeSpan.FromSeconds(i * span.TotalSeconds)) 
    .Subscribe(t => Console.WriteLine("ideal: " + t.ToString("HH:mm:ss.fff"))); 

boundary.Select(i => time.Now) 
    .Subscribe(t => Console.WriteLine("actual: " + t.ToString("HH:mm:ss.fff"))); 

आप देख सकते हैं कि इरादा और टाइमर के वास्तविक समय के अलावा काफी भारी बहाव टिक्स:

ideal: 10:06:40.000 
actual: 10:06:40.034 
actual: 10:06:41.048 
ideal: 10:06:41.000 
actual: 10:06:42.055 
ideal: 10:06:42.000 
ideal: 10:06:43.000 
actual: 10:06:43.067 
actual: 10:06:44.081 
ideal: 10:06:44.000 
ideal: 10:06:45.000 
actual: 10:06:45.095 
actual: 10:06:46.109 
ideal: 10:06:46.000 
ideal: 10:06:47.000 
actual: 10:06:47.123 
actual: 10:06:48.137 
ideal: 10:06:48.000 
... 

मैं भी एक HistoricalScheduler और निश्चित रूप से का इस्तेमाल करते हैं मुझे वहां कोई समस्या नहीं है। मैं मामूली त्रुटियों को सहन कर सकता हूं और मुझे सिस्टम घड़ी में बदलावों की परवाह करने की आवश्यकता नहीं है। उन पर्यवेक्षकों द्वारा ट्रिगर किए गए कोई हेवीवेट ऑपरेशन नहीं हैं।

इसके अलावा, मुझे पता है कि इस blog post में आरएक्स टाइमर बहाव की समस्याओं की लंबी चर्चा है, लेकिन मुझे लगता है कि यह मेरे सिर को लपेटने में सक्षम नहीं है।

समय-समय पर व्यवस्थित टाइमर बहाव के बिना Observable शेड्यूल करने का सही तरीका क्या होगा?

उत्तर

11

आप Observable.Generate इस्तेमाल कर सकते हैं:

var boundary = Observable.Generate(
    0, _ => true, // start condition 
    i => ++i,  // iterate 
    i => i,  // result selector 
    i => start + TimeSpan.FromSeconds(i * span.TotalSeconds), 
    time); 

यह हर यात्रा पूर्ण समय के आधार पर फिर से शेड्यूल होगा।

कुछ नमूने यहां उत्पादन है:

actual: 01:00:44.003 
ideal: 01:00:44.000 
actual: 01:00:44.999 
ideal: 01:00:45.000 
actual: 01:00:46.012 
ideal: 01:00:46.000 
actual: 01:00:47.011 
ideal: 01:00:47.000 
actual: 01:00:48.011 
ideal: 01:00:48.000 
actual: 01:00:49.007 
ideal: 01:00:49.000 
actual: 01:00:50.009 
ideal: 01:00:50.000 
actual: 01:00:51.006 
ideal: 01:00:51.000 

यह बिल्कुल मेल नहीं खाता, मैं कल्पना हंस द्वारा समझाया कारणों की वजह से, लेकिन कोई बहाव है।

संपादित करें:

यहाँ RxSource

// BREAKING CHANGE v2 > v1.x - No more correction for time drift based on absolute time. This 
//        didn't work for large period values anyway; the fractional 
//        error exceeded corrections. Also complicated dealing with system 
//        clock change conditions and caused numerous bugs. 
// 
// - For more precise scheduling, use a custom scheduler that measures TimeSpan values in a 
// better way, e.g. spinning to make up for the last part of the period. Whether or not the 
// values of the TimeSpan period match NT time or wall clock time is up to the scheduler. 
// 
// - For more accurate scheduling wrt the system clock, use Generate with DateTimeOffset time 
// selectors. When the system clock changes, intervals will not be the same as diffs between 
// consecutive absolute time values. The precision will be low (1s range by default). 
+0

धन्यवाद मेरी समस्या को हल करने के लिए बहुत बढ़िया, उत्कृष्ट उत्तर और पर्याप्त सटीक। अफसोस की बात है, मैंने पहले से ही इस पर शासन कर दिया था क्योंकि 'अवलोकन योग्य। जनरेट() 'मुझे [संबंधित परिदृश्य] में सिरदर्द दे रहा है (http://stackoverflow.com/questions/13462713/why-does-observable-generate-throw- सिस्टम-stackoverflowexception)। ऐसा लगता है कि जब भी मैं आरएक्स से संबंधित एक प्रश्न पूछता हूं :-) –

+0

ठीक है, आरएक्स स्रोतों में टिप्पणियों को इंगित करने के लिए धन्यवाद, हर बार जब मैं अपने हार्डवेयर को अच्छी तरह से जानता हूं। ऐसा लगता है कि मुझे उन्हें अधिक बार जांचना चाहिए, अब वे उपलब्ध हैं। –

26

अधिकांश मशीनों पर डिफ़ॉल्ट विंडोज घड़ी इंटरप्ट दर प्रति सेकेंड 64 इंटरप्ट्स है। सीएलआर द्वारा 15.6 मिलीसेकंड तक बढ़ा। यदि आप 1000 मिलीसेकंड के अंतराल के लिए पूछते हैं तो यह एक खुश संख्या नहीं है, कोई अभिन्न divisor नहीं है। निकटतम मैच 64 x 15.6 = 998 (बहुत छोटा) और 65 x 15.6 = 1014 मिलीसेकंड हैं।

जो आप देख रहे हैं, वह 41.048 - 40.034 = 1.014 है। 44.081 - 43.067 = 1.014, आदि।

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

एक और अधिक दृष्टिकोण यह स्वीकार करने के लिए है कि आप कभी अंतराल जोड़कर सटीक समय नहीं रख सकते हैं। 15.6 एमएससी जो सीएलआर उपयोग करता है वह पहले से ही अनुमान है। हमेशा पूर्ण घड़ी के साथ पुनर्मिलन करें। 1000 के बजाय 998 एमसीसी के लिए पूछकर करीब आ जाओ। Etcetera।

+2

यह एक हत्यारा जवाब है से कुछ टिप्पणियों है, वास्तव में महान जवाब upvoted –

+0

वाह,। पौलुस के उत्थान के आधार पर मुझे लगता है कि इस सीमा के आस-पास 'अवलोकनयोग्य। टिमर()' का कोई रास्ता नहीं है।इच्छा है कि मैं आपके और मैथ्यू के दोनों उत्तरों को सही के रूप में चिह्नित कर सकूं। मैंने आरएक्स-विशिष्ट एक के साथ जाने का फैसला किया, लेकिन फिर भी धन्यवाद। –

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