स्टॉपवॉच में हुड के तहत

परिचय


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

DateTime का उपयोग करना


कोड के निष्पादन समय को मापने के लिए DateTime संरचना का उपयोग करना काफी सरल है:

var before = DateTime.Now; SomeOperation(); var spendTime = DateTime.Now - before; 

प्रॉपर्टी DateTime.Now - स्थानीय वर्तमान दिनांक और समय लौटाता है। DateTime.Now प्रॉपर्टी के बजाय, आप DateTime.UtcNow प्रॉपर्टी का उपयोग कर सकते हैं - जो वर्तमान दिनांक और समय को लौटाती है, लेकिन स्थानीय समय क्षेत्र के बजाय, यह यूटीसी समय के रूप में उनका प्रतिनिधित्व करता है, अर्थात, सार्वभौमिक समन्वित समय के रूप में।

 var before = DateTime.UtcNow; SomeOperation(); var spendTime = DateTime.UtcNow - before; 

डेटाइम की संरचना के बारे में कुछ शब्द


शायद कुछ के बारे में सोचा है कि DateTime संरचना क्या है। दिनांक समयरेखा संरचना का मान 100 नैनोसेकंड इकाइयों में मापा जाता है जिसे उपाय कहा जाता है, और सटीक तिथि 1 जनवरी, 0001 ईस्वी सन् 00:00 के बाद से पारित उपायों की संख्या द्वारा दर्शाई गई है।

उदाहरण के लिए, संख्या 628539264000000000 6 अक्टूबर 1992, 00:00:00 का प्रतिनिधित्व करती है।

दिनांक समय संरचना में एक एकल फ़ील्ड होती है, जिसमें पिछले उपायों की संख्या होती है:

 private UInt64 dateData; 

यह भी कहा जाना चाहिए कि .NET 2.0 से शुरू होकर, इस क्षेत्र के 2 सबसे महत्वपूर्ण बिट्स डेटाइम प्रकार को इंगित करते हैं: अनिर्दिष्ट - निर्दिष्ट नहीं, यूटीसी - समन्वित समय, स्थानीय - स्थानीय समय, और शेष 62 बिट्स - टिक्सेस की संख्या। हम इन दोनों बिट्स का अनुरोध आसानी से कर सकते हैं।

DateTime का उपयोग करना क्या बुरा है?


दिनांक समय अंतराल को मापने के लिए DateTime.Now संपत्ति का उपयोग करना एक अच्छा विचार नहीं है, और यहाँ क्यों है:

DateTime.Now
 public static DateTime Now { get { DateTime utc = DateTime.UtcNow; Boolean isAmbiguousLocalDst = false; Int64 offset = TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc(utc, out isAmbiguousLocalDst).Ticks; long tick = utc.Ticks + offset; if (tick > DateTime.MaxTicks) { return new DateTime(DateTime.MaxTicks, DateTimeKind.Local); } if (tick < DateTime.MinTicks) { return new DateTime(DateTime.MinTicks, DateTimeKind.Local); } return new DateTime(tick, DateTimeKind.Local, isAmbiguousLocalDst); } } 


DateTime.Now संपत्ति की गणना DateTime.UtcNow पर आधारित है, अर्थात, समन्वित समय की गणना पहले की जाती है, और फिर समय क्षेत्र ऑफसेट को इसके लिए लागू किया जाता है।

यही कारण है कि DateTime.UtcNow संपत्ति का उपयोग करना अधिक सही होगा, इसकी गणना बहुत तेजी से की जाती है:

DateTime.UtcNow
 public static DateTime UtcNow { get { long ticks = 0; ticks = GetSystemTimeAsFileTime(); return new DateTime(((UInt64)(ticks + FileTimeOffset)) | KindUtc); } } 


DateTime.Now या DateTime.UtcNow का उपयोग करने में समस्या यह है कि उनकी सटीकता निश्चित है। जैसा कि ऊपर कहा गया है

1 टिक = 100 नैनोसेकेंड = 0.1 माइक्रोसेकंड = 0.0001 मिलीसेकंड = 0.0000001 सेकंड

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

स्टॉपवॉच क्लास का उपयोग करना


स्टॉपवॉच वर्ग .NET 2.0 में दिखाई दिया और तब से कोई बदलाव नहीं आया है। यह तरीकों और उपकरणों का एक सेट प्रदान करता है जिसका उपयोग सही समय खर्च करने के लिए किया जा सकता है।

स्टॉपवॉच वर्ग सार्वजनिक एपीआई इस प्रकार है:

गुण
  1. बीता हुआ - कुल बीता हुआ समय लौटाता है;
  2. ElapsedMilliseconds - मिलीसेकंड में कुल बीता समय लौटाता है;
  3. ElapsedTicks - टाइमर टिक में कुल बीता समय लौटाता है;
  4. IsRunning - एक मान दर्शाता है कि स्टॉपवॉच टाइमर चल रहा है या नहीं।

तरीकों
  1. रीसेट - समय अंतराल की माप को रोकता है और बीता हुआ समय रीसेट करता है;
  2. पुनः आरंभ - समय अंतराल को मापना बंद कर देता है, बीते हुए समय को हल करता है और बीते हुए समय को मापना शुरू करता है;
  3. शुरू - एक अंतराल के लिए बीता हुआ समय मापना शुरू या जारी रखता है;
  4. StartNew - स्टॉपवॉच के एक नए उदाहरण को आरंभीकृत करता है, बीता समय संपत्ति को शून्य पर सेट करता है और बीते हुए समय को मापना शुरू करता है;
  5. स्टॉप - अंतराल के लिए बीता समय की माप को रोकता है।

खेतों
  1. आवृत्ति - टाइमर की आवृत्ति रिटर्न प्रति सेकंड उपायों की संख्या के रूप में;
  2. IsHighResolution - इंगित करता है कि क्या टाइमर उच्च-रिज़ॉल्यूशन प्रदर्शन काउंटर पर निर्भर करता है।

कोड जो कुछ स्टेपवॉच विधि के निष्पादन समय को मापने के लिए स्टॉपवॉच वर्ग का उपयोग करता है, वह इस तरह दिख सकता है:

 var sw = new Stopwatch(); sw.Start(); SomeOperation(); sw.Stop(); 

पहली दो पंक्तियों को अधिक संक्षेप में लिखा जा सकता है:

 var sw = Stopwatch.StartNew(); SomeOperation(); sw.Stop(); 

स्टॉपवॉच कार्यान्वयन


स्टॉपवॉच वर्ग एचपीईटी (हाई प्रिसिजन इवेंट टाइमर) पर आधारित है। यह टाइमर माइक्रोसॉफ्ट द्वारा एक बार और सभी के लिए समय मापन की समस्याओं को समाप्त करने के लिए पेश किया गया था। इस टाइमर की आवृत्ति (न्यूनतम 10 मेगाहर्ट्ज) सिस्टम ऑपरेशन के दौरान नहीं बदलती है। प्रत्येक प्रणाली के लिए, विंडोज स्वयं इस टाइमर को लागू करने के लिए किन उपकरणों के साथ निर्धारित करता है।

स्टॉपवॉच वर्ग में निम्नलिखित फ़ील्ड शामिल हैं:

 private const long TicksPerMillisecond = 10000; private const long TicksPerSecond = TicksPerMillisecond * 1000; private bool isRunning; private long startTimeStamp; private long elapsed; private static readonly double tickFrequency; 

TicksPerMillisecond - 1 मिलीसेकंड में DateTime उपायों की संख्या निर्धारित करता है;
TicksPerSecond - 1 सेकंड में DateTime उपायों की संख्या निर्धारित करता है;

isRunning - निर्धारित करता है कि क्या वर्तमान उदाहरण चल रहा है (चाहे प्रारंभ विधि को कहा गया था);
startTimeStamp - लॉन्च के समय उपायों की संख्या;
बीता हुआ - खर्च किए गए उपायों की कुल संख्या;

टिकफ्रीक्वेंसी - स्टॉपवॉच के उपायों को डेटाइम में बदलना आसान बनाता है।

एचपीईटी टाइमर की उपस्थिति के लिए स्टैटिक कंस्ट्रक्टर चेक करता है और यदि नहीं, तो स्टॉपवॉच आवृत्ति को डेटाइम आवृत्ति पर सेट किया जाता है।

स्टैटिक कंस्ट्रक्टर स्टॉपवॉच
 static Stopwatch() { bool succeeded = SafeNativeMethods.QueryPerformanceFrequency(out Frequency); if(!succeeded) { IsHighResolution = false; Frequency = TicksPerSecond; tickFrequency = 1; } else { IsHighResolution = true; tickFrequency = TicksPerSecond; tickFrequency /= Frequency; } } 


इस वर्ग का मुख्य परिदृश्य ऊपर दिखाया गया था: प्रारंभ विधि को कॉल करना, जिसका समय मापा जाना चाहिए, और फिर स्टॉप विधि को कॉल करना।

प्रारंभ विधि का कार्यान्वयन बहुत सरल है - यह उपायों की प्रारंभिक संख्या को याद करता है:

प्रारंभ
 public void Start() { if (!isRunning) { startTimeStamp = GetTimestamp(); isRunning = true; } } 


यह कहा जाना चाहिए कि पहले से ही मापने वाले उदाहरण पर स्टार्ट विधि को कॉल करने से कुछ भी नहीं होता है।

स्टॉप विधि बस के रूप में सरल है:

बंद करो
 public void Stop() { if (isRunning) { long endTimeStamp = GetTimestamp(); long elapsedThisPeriod = endTimeStamp - startTimeStamp; elapsed += elapsedThisPeriod; isRunning = false; if (elapsed < 0) { // When measuring small time periods the StopWatch.Elapsed* // properties can return negative values. This is due to // bugs in the basic input/output system (BIOS) or the hardware // abstraction layer (HAL) on machines with variable-speed CPUs // (eg Intel SpeedStep). elapsed = 0; } } } 


स्टॉप विधि को रोकना उदाहरण पर कॉल करना भी विफल रहता है।

दोनों तरीके GetTimestamp () कॉल का उपयोग करते हैं - जो कॉल के समय उपायों की संख्या लौटाता है:

GetTimestamp
 public static long GetTimestamp() { if (IsHighResolution) { long timestamp = 0; SafeNativeMethods.QueryPerformanceCounter(out timestamp); return timestamp; } else { return DateTime.UtcNow.Ticks; } } 


एचपीईटी (उच्च परिशुद्धता घटना टाइमर) के साथ, स्टॉपवॉच उपाय डेटाइम से अलग हैं।

निम्नलिखित कोड

 Console.WriteLine(Stopwatch.GetTimestamp()); Console.WriteLine(DateTime.UtcNow.Ticks); 

मेरे कंप्यूटर पर प्रदर्शित होता है

 5201678165559 635382513439102209 

DateTime या TimeSpan बनाने के लिए स्टॉपवॉच टिक्स का उपयोग करना गलत है। अभिलेख

 var time = new TimeSpan(sw.ElaspedTicks); 

स्पष्ट कारणों के लिए, गलत परिणाम देगा।

स्टॉपवॉच नहीं, डेटटाइम उपायों को प्राप्त करने के लिए, आपको Elapsed और ElapsedMilliseconds गुणों का उपयोग करने या मैन्युअल रूप से रूपांतरण करने की आवश्यकता है। स्टॉपवॉच उपायों को डेटाइम उपायों में बदलने के लिए, निम्न विधि का उपयोग कक्षा में किया जाता है:

GetElapsedDateTimeTicks
 private long GetElapsedDateTimeTicks() { long rawTicks = GetRawElapsedTicks();// get Stopwatch ticks if (IsHighResolution) { // convert high resolution perf counter to DateTime ticks double dticks = rawTicks; dticks *= tickFrequency; return unchecked((long)dticks); } else { return rawTicks; } } 


संपत्ति कोड अपेक्षा के अनुसार दिखता है:

बीता हुआ, एलास्पेडमिलिसकंड्स
 public TimeSpan Elapsed { get { return new TimeSpan(GetElapsedDateTimeTicks()); } } public long ElapsedMilliseconds { get { return GetElapsedDateTimeTicks() / TicksPerMillisecond; } } 


स्टॉपवॉच का उपयोग करने के बारे में क्या बुरा है?


MSDN के साथ इस वर्ग के लिए एक नोट कहता है: मल्टीप्रोसेसर कंप्यूटर पर, इससे कोई फर्क नहीं पड़ता कि कौन सा प्रोसेसर थ्रेड चला रहा है। हालांकि, BIOS या अमूर्त उपकरण परत (HAL) में त्रुटियों के कारण, आप विभिन्न प्रोसेसर के समय की गणना के विभिन्न परिणाम प्राप्त कर सकते हैं।

इससे बचने के लिए, स्टॉप मेथड में एक if (बीता हुआ <0) कंडीशन है।

मुझे बहुत सारे लेख मिले जिनके लेखकों को एचपीईटी के गलत संचालन के कारण समस्याओं का सामना करना पड़ा।

एचपीईटी की अनुपस्थिति में स्टॉपवॉच डेटटाइम घड़ियों का उपयोग करता है, इसलिए डेटटाइम के स्पष्ट उपयोग पर इसका लाभ खो जाता है। इसके अलावा, आपको स्टॉपवॉच द्वारा किए गए विधि कॉल और चेक पर खर्च किए गए समय को ध्यान में रखना होगा, खासकर अगर यह एक लूप में होता है।

मोनो में स्टॉपवॉच


मैं सोच रहा था कि मोनो में स्टॉपवॉच वर्ग कैसे लागू किया जाता है, क्योंकि मुझे एचपीईटी के साथ काम करने के लिए मूल विंडोज कार्यों पर भरोसा नहीं करना है।

 public static readonly long Frequency = 10000000; public static readonly bool IsHighResolution = true; 

मोनो में स्टॉपवॉच हमेशा डेटाइम घड़ियों का उपयोग करती है, और इसलिए डेटटाइम के स्पष्ट उपयोग पर इसका कोई लाभ नहीं है, सिवाय इसके कि कोड अधिक पठनीय है।

Environment.TickCount


यह पर्यावरण के बारे में भी कहा जाना चाहिए। टिकट संपत्ति, जो सिस्टम के बूट होने के बाद (बीता हुआ समय) समाप्त हुआ समय देता है।

इस संपत्ति का मूल्य सिस्टम टाइमर से पुनर्प्राप्त किया जाता है और एक हस्ताक्षरित 32-बिट पूर्णांक के रूप में संग्रहीत किया जाता है। इसलिए, यदि सिस्टम लगातार चल रहा है, तो टिककाउंट संपत्ति का मूल्य लगभग 24.9 दिनों के लिए बढ़ जाएगा, शून्य से शुरू होता है और Int32.MaxValue के मूल्य के साथ समाप्त होता है, जिसके बाद इसे Int32.MinVueue के मान पर रीसेट कर दिया जाएगा, जो एक नकारात्मक संख्या है, और फिर से बढ़ना शुरू हो जाएगा अगले 24.9 दिनों में खरोंच।

इस संपत्ति का उपयोग करना GetTickCount () सिस्टम फ़ंक्शन के लिए एक कॉल से मेल खाता है, जो बहुत तेज़ है, क्योंकि यह केवल संबंधित काउंटर का मूल्य लौटाता है। हालांकि, इसकी सटीकता कम है (10 मिलीसेकंड), क्योंकि काउंटर को बढ़ाने के लिए कंप्यूटर की वास्तविक समय घड़ी द्वारा उत्पन्न व्यवधान का उपयोग किया जाता है।

निष्कर्ष


विंडोज ऑपरेटिंग सिस्टम में कई टाइमर होते हैं (फ़ंक्शन जो आपको समय अंतराल को मापने की अनुमति देते हैं)। उनमें से कुछ सटीक हैं, लेकिन तेज़ नहीं हैं (टाइमगेट टाइम), अन्य तेज़ हैं, लेकिन सटीक नहीं हैं (GetTickCount, GetSystemTime), और तीसरा, Microsoft के अनुसार तेज़ और सटीक हैं। उत्तरार्द्ध में HPET टाइमर और फ़ंक्शन शामिल हैं जो आपको इसके साथ काम करने की अनुमति देते हैं: QueryPerformanceFrequency, QueryPerformanceCounter।

स्टॉपवॉच वर्ग वास्तव में HPET पर एक प्रबंधित आवरण है। इस वर्ग के उपयोग के दोनों फायदे हैं (समय अंतराल के अधिक सटीक माप) और नुकसान (BIOS में त्रुटियां, एचएएल गलत परिणाम दे सकते हैं), और एचपीईटी की अनुपस्थिति में, इसके फायदे पूरी तरह से खो गए हैं।

स्टॉपवॉच क्लास का उपयोग करना है या नहीं, यह आपके ऊपर है। हालांकि, यह मुझे लगता है कि इस वर्ग के फायदे अभी भी नुकसान से अधिक हैं।

Source: https://habr.com/ru/post/In226279/


All Articles