2012-09-14 26 views
9

नोड.जेएस के साथ आने वाली परियोजना के लिए मुझे आवधिक समय पर विभिन्न हाउसकीपिंग कार्यों को करने की आवश्यकता है। विशेष रूप से कुछ मिलें प्रत्येक मिलीसेकंड, दूसरों को हर 20 एमएस (प्रति सेकंड 50 बार) और फिर भी हर दूसरे दूसरों को। तो मैंने मजेदार परिणामों के साथ setInterval() का उपयोग करने के बारे में सोचा: कई फ़ंक्शन कॉल छोड़े जा रहे थे।node.js: setInterval() कॉल छोड़ने

बेंचमार्क मैं इस्तेमाल किया प्रकार है:

var counter = 0; 
var seconds = 0; 
var short = 1; 
setInterval(function() { 
     counter ++; 
    }, short); 
setInterval(function() { 
     seconds ++; 
     log('Seconds: ' + seconds + ', counter: ' + 
      counter + ', missed ' + 
      (seconds * 1000/short - counter)); 
    }, 1000); 

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

2012-09-14T23:03:32.780Z Seconds: 1, counter: 869, missed 131 
2012-09-14T23:03:33.780Z Seconds: 2, counter: 1803, missed 197 
2012-09-14T23:03:34.781Z Seconds: 3, counter: 2736, missed 264 
... 
2012-09-14T23:03:41.783Z Seconds: 10, counter: 9267, missed 733 

कई समारोह कॉल को छोड़ दिया जाता है:

यह इस प्रकार से व्यवहार करने के तरीके कम टाइमर 1 एमएस है। यहां यह 10 एमएस के लिए है:

2012-09-14T23:01:56.363Z Seconds: 1, counter: 93, missed 7 
2012-09-14T23:01:57.363Z Seconds: 2, counter: 192, missed 8 
2012-09-14T23:01:58.364Z Seconds: 3, counter: 291, missed 9 
... 
2012-09-14T23:02:05.364Z Seconds: 10, counter: 986, missed 14 

बेहतर, लेकिन मोटे तौर पर एक समारोह कॉल हर सेकेंड छोड़ दिया जाता है। और 20 एमएस के लिए:

2012-09-14T23:07:18.713Z Seconds: 1, counter: 46, missed 4 
2012-09-14T23:07:19.713Z Seconds: 2, counter: 96, missed 4 
2012-09-14T23:07:20.712Z Seconds: 3, counter: 146, missed 4 
... 
2012-09-14T23:07:27.714Z Seconds: 10, counter: 495, missed 5 
अंत में 100 एमएस के लिए

:

2012-09-14T23:04:25.804Z Seconds: 1, counter: 9, missed 1 
2012-09-14T23:04:26.803Z Seconds: 2, counter: 19, missed 1 
2012-09-14T23:04:27.804Z Seconds: 3, counter: 29, missed 1 
... 
2012-09-14T23:04:34.805Z Seconds: 10, counter: 99, missed 1 

इस मामले में यह छोड़ देता है तो बहुत कुछ कॉल (अंतराल 33 सेकंड के बाद 2 की वृद्धि हुई और 3 108 के बाद सेकंड के लिए

संख्या में भिन्नता है, लेकिन रन के बीच आश्चर्यजनक रूप से संगत कर रहे हैं: पहले 1 एमएस बेंचमार्क चल रहा है तीन बार 9267, 9259 और 9253.

के 10 सेकंड के बाद एक देरी झुकेंगे मेरे पास कोई संदर्भ पाया है इस विशेष समस्या के लिए। यह much cited Ressig post और संबंधित जावास्क्रिप्ट प्रश्नों के बहुत सारे हैं, लेकिन अधिकांश मानते हैं कि कोड ब्राउज़र में चलता है न कि node.js. में।

अब डरावनी प्रश्न के लिए: यहां क्या चल रहा है? सिर्फ मजाक करना; स्पष्ट रूप से कार्य कॉल छोड़ दिया जा रहा है। लेकिन मैं पैटर्न देखने में असफल रहा। मैंने सोचा कि लंबे चक्र छोटे बच्चों को रोक सकते हैं, लेकिन यह 1 एमएस मामले में कोई समझ नहीं आता है। लघु चक्र फ़ंक्शन कॉल ओवरलैपिंग नहीं कर रहे हैं क्योंकि वे केवल एक चर अद्यतन करते हैं, और node.js प्रक्रिया 1 एमएस के एक छोटे चक्र के साथ भी 5% CPU के करीब है। लोड औसत औसत हालांकि 0.50 पर है। मुझे नहीं पता कि क्यों एक हजार कॉल मेरे सिस्टम पर जोर दे रहे हैं, हालांकि, क्योंकि node.js many more clients perfectly को संभालता है; यह सच होना चाहिए कि setInterval() is CPU intensive (या मैं कुछ गलत कर रहा हूं)।

एक स्पष्ट समाधान कॉल अब टाइमर कई बार का उपयोग कर, और फिर कम चक्र समारोह चलाने कॉल एक छोटी घड़ी अनुकरण करने के लिए समूह कार्य करने के लिए है। फिर लंबे चक्र को "झाड़ू वैगन" के रूप में उपयोग करें जो कम अंतराल में किसी भी कॉल को याद करता है। एक उदाहरण: 20 एमएस और 1000 एमएस सेट इंटरवल() कॉल सेट करें। 1 एमएस कॉल के लिए: 20 एमएस कॉलबैक में उन्हें 20 बार कॉल करें। 1000 एमएस लिए कॉल करें: जाँच कितनी बार 20ms समारोह बुलाया गया है (उदाहरण के लिए 47), कर किसी भी शेष कॉल (जैसे 3)। लेकिन इस योजना के बाद से कॉल रोचक तरीके से ओवरलैप हो सकता है, थोड़ा जटिल होने जा रहा है; यह भी नियमित रूप से हालांकि यह यह की तरह लग सकता है नहीं होगा।

असली सवाल है: यह बेहतर है, या तो setInterval() या Node.js के भीतर अन्य टाइमर के साथ किया जा सकता है? अग्रिम में धन्यवाद।इस दस्तावेज़ के पर

उत्तर

10

जावास्क्रिप्ट में सेट अंतराल कार्यों सटीक नहीं हैं। आपको उच्च रिज़ॉल्यूशन टाइमर का उपयोग करने का प्रयास करना चाहिए। Building accurate Timers in javascript

+0

कैसे? कौन सा संकल्प टाइमर, एक पुस्तकालय? – alexfernandez

+0

google.http: //www.sitepoint में कई उच्च रिज़ॉल्यूशन टाइमर स्क्रिप्ट हैं।कॉम/बनाने-सटीक-टाइमर-इन-जावास्क्रिप्ट/ – zer02

+0

यह वर्तमान समस्या को हल नहीं करेगा। –

8

देखो: http://nodejs.org/api/timers.html#timers_settimeout_callback_delay_arg

यह ध्यान रखें कि अपने कॉलबैक शायद बिल्कुल मिलीसेकेंड में देरी में नहीं बुलाया जाएगा महत्वपूर्ण है - Node.js जब कॉलबैक को सक्रिय कर देगा का सही समय के बारे में कोई गारंटी नहीं देता , न ही ऑर्डरिंग चीजों में आग लग जाएगी। कॉलबैक को निर्दिष्ट समय के लिए जितना संभव हो उतना करीब कहा जाएगा।

ऐसा इसलिए होता है क्योंकि एप्लिकेशन कोड ईवेंट लूप को अवरुद्ध करता है। सभी टाइमर और आई/ओ घटनाओं को केवल nextTick पर संभाला जा सकता है।

आप इस कोड के साथ इस व्यवहार देख सकते हैं: पुनरावृत्तियों गिनती और परिणाम देखें बदलने के लिए

setInterval(function() { 
    console.log(Date.now()); 
    for (var i = 0; i < 100000000; i++) { 
    } 
}, 1); 

प्रयास करें।

आदर्श रूप से, टाइमर ठीक से ट्रिगर हो जाएगा यदि अनुप्रयोग टिक एक से भी कम समय तक टिकेगा। लेकिन यह वास्तविक अनुप्रयोग में व्यावहारिक नहीं है।

+0

मैंने उस संदर्भ को पढ़ा था, लेकिन यह क्यों नहीं समझाता है। मेरे बेंचमार्क में मेरे पास इवेंट लूप को अवरुद्ध करने वाला कोई एप्लिकेशन कोड नहीं है। अगलीटिक का संदर्भ दिलचस्प है, धन्यवाद। हालांकि यह केवल एक स्तर दूर समस्या को धक्का देता है: कितनी बार process.nextTick() आग? क्यों, और इसे बदला जा सकता है? – alexfernandez

+0

नहीं, मेरा मतलब 'process.nextTick() 'समाधान के रूप में नहीं था। मैं कहना चाहता था कि एक घटना-लूप पुनरावृत्ति के निष्पादन के समय टाइमर और आई/ओ घटनाओं को संभालने का कोई तरीका नहीं है। –

+0

समझा। लेकिन भार की अनुपस्थिति में एक घटना-लूप पुनरावृत्ति कितनी देर तक है? – alexfernandez

2

उत्तर वादिम और ज़ीर 02 द्वारा दिए गए लोगों का संयोजन होता है, इसलिए मैं यहां एक लेखन-पत्र छोड़ रहा हूं। जैसा कि वादिम ने कहा था, सिस्टम बहुत लगातार अपडेट का सामना नहीं कर सकता है, और सिस्टम में कुछ लोड जोड़ने में मदद नहीं मिल रही है। या बल्कि रनटाइम का सामना नहीं कर सकता; यदि आवश्यक हो तो सिस्टम प्रत्येक मिलीसेकंड को कॉलबैक फायर करने में सक्षम होना चाहिए, लेकिन कुछ अस्पष्ट कारणों के लिए अक्सर यह नहीं करना चाहता।

समाधान accurate timers का उपयोग करना है, क्योंकि zer02 ने टिप्पणी की थी। नाम से गुमराह मत बनो; उपयोग की जाने वाली तंत्र एक ही सेटटाइमआउट() है, लेकिन देरी को तब तक समायोजित किया जाता है जब तक कि टाइमर को आग लगाना न पड़े। तो, यदि समय खत्म हो गया है तो "सटीक टाइमर" सेटटाइमआउट (कॉलबैक, 0) को कॉल करेगा जो तुरंत चलाया जाता है। सिस्टम लोड आश्चर्यजनक रूप से, setInterval() से कम है: मेरे बहुत अवैज्ञानिक नमूने में, 5% की बजाय CPU का लगभग 2%।

यह सरल समारोह काम में आ सकता है:

/** 
* A high resolution timer. 
*/ 
function timer(delay, callback) 
{ 
    // self-reference 
    var self = this; 

    // attributes 
    var counter = 0; 
    var start = new Date().getTime(); 

    /** 
    * Delayed running of the callback. 
    */ 
    function delayed() 
    { 
     callback(delay); 
     counter ++; 
     var diff = (new Date().getTime() - start) - counter * delay; 
     setTimeout(delayed, delay - diff); 
    } 

    // start timer 
    delayed(); 
    setTimeout(delayed, delay); 
} 

उपयोग करने के लिए, बस new timer(delay, callback); कहते हैं। (हाँ, मैंने पैरामीटर को ऑर्डर को उलट दिया क्योंकि कॉलबैक पहले बहुत परेशान है।)

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

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