ध्यान दें कि मैं ऐसा कुछ पूछ रहा हूं जो System.Threading.Timer
जैसे कुछ का उपयोग कर कॉलबैक फ़ंक्शन को हर 15 एमएस से अधिक बार कॉल करेगा। मैं System.Diagnostics.Stopwatch
या यहां तक कि QueryPerformanceCounter
जैसे कुछ का उपयोग करके कोड के टुकड़े को सटीक रूप से सही करने के बारे में नहीं पूछ रहा हूं।क्यों .NET टाइमर 15 एमएस रिज़ॉल्यूशन तक सीमित हैं?
इसके अलावा, मैं संबंधित प्रश्नों पढ़ा है:
Accurate Windows timer? System.Timers.Timer() is limited to 15 msec
न तो जिनमें से मेरे सवाल के लिए एक उपयोगी जवाब आपूर्ति करती है।
इसके अलावा, की सिफारिश की MSDN लेख, Implement a Continuously Updating, High-Resolution Time Provider for Windows, चीजें समय के बजाय टिक की एक सतत स्ट्रीम प्रदान करने के बारे में है।
इसके साथ कहा। । ।
वहाँ नेट टाइमर वस्तुओं के बारे में बुरा जानकारी की एक पूरी बहुत सी चीज़ें हैं। उदाहरण के लिए, System.Timers.Timer
"सर्वर अनुप्रयोगों के लिए अनुकूलित एक उच्च प्रदर्शन टाइमर" के रूप में बिल किया जाता है। और System.Threading.Timer
किसी भी तरह से द्वितीय श्रेणी के नागरिक माना जाता है। पारंपरिक ज्ञान यह है कि System.Threading.Timer
विंडोज Timer Queue Timers के आसपास एक रैपर है और System.Timers.Timer
पूरी तरह से कुछ और है।
वास्तविकता बहुत अलग है। System.Timers.Timer
System.Threading.Timer
के आस-पास केवल एक पतला घटक रैपर है (केवल System.Timers.Timer
के अंदर देखने के लिए परावर्तक या आईएलडीएएसएम का उपयोग करें और आपको System.Threading.Timer
का संदर्भ दिखाई देगा), और इसमें कुछ कोड है जो स्वचालित थ्रेड सिंक्रनाइज़ेशन प्रदान करेगा ताकि आपको इसे करने की आवश्यकता न हो।
System.Threading.Timer
, क्योंकि यह टाइमर कतार टाइमर के लिए एक रैपर नहीं है। कम से कम 2.0 रनटाइम में नहीं, जिसका उपयोग .NET 2.0 से .NET 3.5 के माध्यम से किया गया था। साझा स्रोत सीएलआई के साथ कुछ मिनट दिखाते हैं कि रनटाइम टाइमर कतार टाइमर के समान ही अपनी टाइमर कतार लागू करता है, लेकिन वास्तव में Win32 फ़ंक्शंस को कभी भी कॉल नहीं करता है।
ऐसा लगता है कि .NET 4.0 क्रम भी अपने स्वयं के टाइमर कतार लागू करता है। मेरा परीक्षण कार्यक्रम (नीचे देखें) .NET 4.0 के तहत समान परिणाम प्रदान करता है क्योंकि यह .NET 3.5 के अंतर्गत होता है। मैंने टाइमर क्यूई टाइमर के लिए अपना स्वयं का प्रबंधित रैपर बनाया है और साबित किया है कि मुझे 1 एमएस रिज़ॉल्यूशन (काफी अच्छी सटीकता के साथ) मिल सकता है, इसलिए मुझे लगता है कि मैं सीएलआई स्रोत गलत पढ़ रहा हूं।
सबसे पहले, क्या इतनी धीमी गति से होने के लिए टाइमर कतार के क्रम के कार्यान्वयन का कारण बनता है:
मैं दो प्रश्न हैं? मैं 15 एमएस रिज़ॉल्यूशन से बेहतर नहीं हो सकता, और सटीकता -1 से +30 एमएस की सीमा में प्रतीत होती है। यही है, अगर मैं 24 एमएस पूछता हूं, तो मुझे 23 से 54 एमएस के अलावा कहीं भी टिक मिलेंगे। मुझे लगता है कि मैं जवाब को ट्रैक करने के लिए सीएलआई स्रोत के साथ कुछ और समय बिता सकता हूं, लेकिन सोचा कि यहां किसी को पता चल सकता है।
दूसरा, और मुझे लगता है कि यह जवाब देने के लिए कठिन है, यही कारण है कि टाइमर कतार टाइमर का उपयोग नहीं? मुझे एहसास है कि .NET 1.x को Win9x पर चलाना था, जिसमें उन एपीआई नहीं थे, लेकिन वे विंडोज 2000 के बाद से मौजूद हैं, जो मुझे याद है कि .NET 2.0 के लिए न्यूनतम आवश्यकता सही थी। क्या ऐसा इसलिए है क्योंकि सीएलआई को गैर-विंडोज़ बॉक्स पर चलाना पड़ा था?
मेरे टाइमर परीक्षण कार्यक्रम:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
namespace TimerTest
{
class Program
{
const int TickFrequency = 5;
const int TestDuration = 15000; // 15 seconds
static void Main(string[] args)
{
// Create a list to hold the tick times
// The list is pre-allocated to prevent list resizing
// from slowing down the test.
List<double> tickTimes = new List<double>(2 * TestDuration/TickFrequency);
// Start a stopwatch so we can keep track of how long this takes.
Stopwatch Elapsed = Stopwatch.StartNew();
// Create a timer that saves the elapsed time at each tick
Timer ticker = new Timer((s) =>
{
tickTimes.Add(Elapsed.ElapsedMilliseconds);
}, null, 0, TickFrequency);
// Wait for the test to complete
Thread.Sleep(TestDuration);
// Destroy the timer and stop the stopwatch
ticker.Dispose();
Elapsed.Stop();
// Now let's analyze the results
Console.WriteLine("{0:N0} ticks in {1:N0} milliseconds", tickTimes.Count, Elapsed.ElapsedMilliseconds);
Console.WriteLine("Average tick frequency = {0:N2} ms", (double)Elapsed.ElapsedMilliseconds/tickTimes.Count);
// Compute min and max deviation from requested frequency
double minDiff = double.MaxValue;
double maxDiff = double.MinValue;
for (int i = 1; i < tickTimes.Count; ++i)
{
double diff = (tickTimes[i] - tickTimes[i - 1]) - TickFrequency;
minDiff = Math.Min(diff, minDiff);
maxDiff = Math.Max(diff, maxDiff);
}
Console.WriteLine("min diff = {0:N4} ms", minDiff);
Console.WriteLine("max diff = {0:N4} ms", maxDiff);
Console.WriteLine("Test complete. Press Enter.");
Console.ReadLine();
}
}
}
अच्छा सवाल! मुझे दिलचस्पी है अगर किसी को वास्तव में इसमें अंतर्दृष्टि है। एसओ पर क्लियर टीम से कोई भी? –
मैं शर्त लगाता हूं कि Win9x में भी कर्नेल में टिकटें थीं। यह सब के बाद एक preemptive कार्य वातावरण था। सभी shitty लेकिन अभी भी असली multitask। इसलिए आप हस्तक्षेप के बिना छूट नहीं कर सकते हैं, और वे एचटीसी (64 हर्ट्ज) के आधार पर नियमित हार्डवेयर टाइमर से विशेष रूप से 90 के दशक में आग लगते हैं। आप ईवेंट कतार के बिना जीयूआई कैसे करते हैं? टाइमर घटनाओं को कर्नेल द्वारा इवेंट कतार में धकेल दिया जाता है, इसके चारों ओर कोई रास्ता नहीं है क्योंकि आपका ऐप कतार के लिए कुछ भी नहीं कर रहा है, यह निर्धारित है। –