c# सी#में उच्च संकल्प टाइमर




timer high-resolution (3)

क्या कोई उच्च रिज़ॉल्यूशन टाइमर है जो हर बार टाइमर समाप्त हो जाता है, जैसे कि System.TimerSystem.Timer वर्ग की तरह? मुझे हर एमएस के Elapse को एक उच्च संकल्प टाइमर की आवश्यकता है

मैं पदों में चल रहा हूं जो बताते हैं कि स्टॉपवॉच उच्च प्रस्तावों को माप सकता है, लेकिन मैं समय का आकलन नहीं करना चाहता, मैं 1 एमएस का अंतराल बनाना चाहता हूं।

क्या नेट पर कुछ है या क्या मैं अपना खुद का उच्च रिज़ टाइमर लिख रहा हूं?


नई प्रणाली बनाने का प्रयास करें। System.Threading.Thread.SleepSystem.Threading.Thread और System.Threading.Thread का प्रयोग करके।

var thrd = new Syatem.Threading.Thread(() => {
    while (true) {
        // do something
        System.Threading.Thread.Sleep(1); // wait 1 ms
    }
});

thrd.Start();

स्टॉपवॉच पर आधारित एक उच्च रिज़ॉल्यूशन टाइमर हो सकता है जो आजकल सिस्टम पर 1 एमएमएस रिज़ॉल्यूशन से भी बेहतर प्रदान कर सकता है।

यहां स्टैक ओवरफ्लो पर मेरा दूसरा जवाब है https://.com/a/45097518/548894

एक कार्यान्वयन https://gist.github.com/DraTeots/436019368d32007284f8a12f1ba0f545

  1. यह सभी प्लेटफार्मों पर काम करता है और जहां भी StopWatch.IsHighPrecision == true है। उच्च StopWatch.IsHighPrecision == true

  2. इसकी समाप्त हुई घटना को गैर अतिव्यापी होने की गारंटी है (जो कि जानना ज़रूरी हो सकता है, क्योंकि ईवेंट हैंडलर के अंदर स्थित राज्य परिवर्तन बहु थ्रेडेड पहुंच से असुरक्षित छोड़ दिया जा सकता है)

यहां इसका उपयोग कैसे किया जाता है:

Console.WriteLine($"IsHighResolution = {HighResolutionTimer.IsHighResolution}");
Console.WriteLine($"Tick time length = {HighResolutionTimer.TickLength} [ms]");

var timer = new HighResolutionTimer(0.5f);

// UseHighPriorityThread = true, sets the execution thread 
// to ThreadPriority.Highest.  It doesn't provide any precision gain
// in most of the cases and may do things worse for other threads. 
// It is suggested to do some studies before leaving it true
timer.UseHighPriorityThread = false;

timer.Elapsed += (s, e) => { /*... e.Delay*/ }; // The call back with real delay info
timer.Start();  
timer.Stop();    // by default Stop waits for thread.Join()
                 // which, if called not from Elapsed subscribers,
                 // would mean that all Elapsed subscribers
                 // are finished when the Stop function exits 
timer.Stop(joinThread:false)   // Use if you don't care and don't want to wait

यहां एक बेंचमार्क (और एक लाइव उदाहरण) है:
https://gist.github.com/DraTeots/5f454968ae84122b526651ad2d6ef2a3

Windows 10 पर 0.5 एमएस के लिए टाइमर सेट करने के परिणाम:

यह भी उल्लेखनीय है कि:

  1. मैं उबंटू पर मोनो पर एक ही सटीक था

  2. बेंचमार्क के साथ खेलते समय, अधिकतम और एक बहुत ही दुर्लभ विचलन मैंने देखा जो लगभग 0.5 एमएस था (जो शायद कुछ भी नहीं है, यह रीयलटाइम सिस्टम नहीं है, लेकिन फिर भी उल्लेख के लायक है)

  3. स्टॉपवॉच टिक्स टाइमस्पेन टैक्स नहीं हैं। उस विंडोज़ 10 मशीन पर उच्चरेशनलटाइमेटर। टेक्सलैंपम 0.23 [एनएस] है।


इसमें कुछ भी नहीं है जो मैं जानता हूं। विंडोज में मल्टीमीडिया टाइमर एपीआई के माध्यम से उच्च रिज़ॉल्यूशन टाइमर इवेंट्स के लिए एक तंत्र है । नीचे एक त्वरित उदाहरण है जो मुझे काम करने के लिए प्रतीत होता है। यहां भी एक अच्छा उदाहरण लगता है

मैं नोट करेगा कि यह एपीआई सिस्टम की व्यापक सेटिंग्स को बदलती है जो सिस्टम प्रदर्शन को नीचा कर सकती हैं, इसलिए खरीदार सावधान रहना परीक्षण के प्रयोजनों के लिए, मैं इस बात को ध्यान में रखेगा कि समय की पुष्टि करने के लिए टाइमर कितनी बार गोलीबारी कर रहा है, डिवाइस को आप अनुकरण करने की कोशिश कर रहे हैं। खिड़कियां एक वास्तविक समय के ओएस नहीं हैं, इसलिए आपके सिस्टम पर भार से एमएम टाइमर को विलंब हो सकता है जिसके परिणामस्वरूप 100 एमएस के अंतराल का कारण बन सकता है जिसमें 100 उत्क्रांतियां होती हैं। एमएम टाइमर पर कुछ अतिरिक्त पठन

class Program
{
    static void Main(string[] args)
    {
        TestThreadingTimer();
        TestMultimediaTimer();
    }

    private static void TestMultimediaTimer()
    {
        Stopwatch s = new Stopwatch();
        using (var timer = new MultimediaTimer() { Interval = 1 })
        {
            timer.Elapsed += (o, e) => Console.WriteLine(s.ElapsedMilliseconds);
            s.Start();
            timer.Start();
            Console.ReadKey();
            timer.Stop();
        }
    }

    private static void TestThreadingTimer()
    {
        Stopwatch s = new Stopwatch();
        using (var timer = new Timer(o => Console.WriteLine(s.ElapsedMilliseconds), null, 0, 1))
        {
            s.Start();
            Console.ReadKey();
        }
    }

}

public class MultimediaTimer : IDisposable
{
    private bool disposed = false;
    private int interval, resolution;
    private UInt32 timerId; 

    // Hold the timer callback to prevent garbage collection.
    private readonly MultimediaTimerCallback Callback;

    public MultimediaTimer()
    {
        Callback = new MultimediaTimerCallback(TimerCallbackMethod);
        Resolution = 5;
        Interval = 10;
    }

    ~MultimediaTimer()
    {
        Dispose(false);
    }

    public int Interval
    {
        get
        {
            return interval;
        }
        set
        {
            CheckDisposed();

            if (value < 0)
                throw new ArgumentOutOfRangeException("value");

            interval = value;
            if (Resolution > Interval)
                Resolution = value;
        }
    }

    // Note minimum resolution is 0, meaning highest possible resolution.
    public int Resolution
    {
        get
        {
            return resolution;
        }
        set
        {
            CheckDisposed();

            if (value < 0)
                throw new ArgumentOutOfRangeException("value");

            resolution = value;
        }
    }

    public bool IsRunning
    {
        get { return timerId != 0; }
    }

    public void Start()
    {
        CheckDisposed();

        if (IsRunning)
            throw new InvalidOperationException("Timer is already running");

        // Event type = 0, one off event
        // Event type = 1, periodic event
        UInt32 userCtx = 0;
        timerId = NativeMethods.TimeSetEvent((uint)Interval, (uint)Resolution, Callback, ref userCtx, 1);
        if (timerId == 0)
        {
            int error = Marshal.GetLastWin32Error();
            throw new Win32Exception(error);
        }
    }

    public void Stop()
    {
        CheckDisposed();

        if (!IsRunning)
            throw new InvalidOperationException("Timer has not been started");

        StopInternal();
    }

    private void StopInternal()
    {
        NativeMethods.TimeKillEvent(timerId);
        timerId = 0;
    }

    public event EventHandler Elapsed;

    public void Dispose()
    {
        Dispose(true);
    }

    private void TimerCallbackMethod(uint id, uint msg, ref uint userCtx, uint rsv1, uint rsv2)
    {
        var handler = Elapsed;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }

    private void CheckDisposed()
    {
        if (disposed)
            throw new ObjectDisposedException("MultimediaTimer");
    }

    private void Dispose(bool disposing)
    {
        if (disposed)
            return;

        disposed = true;
        if (IsRunning)
        {
            StopInternal();
        }

        if (disposing)
        {
            Elapsed = null;
            GC.SuppressFinalize(this);
        }
    }
}

internal delegate void MultimediaTimerCallback(UInt32 id, UInt32 msg, ref UInt32 userCtx, UInt32 rsv1, UInt32 rsv2);

internal static class NativeMethods
{
    [DllImport("winmm.dll", SetLastError = true, EntryPoint = "timeSetEvent")]
    internal static extern UInt32 TimeSetEvent(UInt32 msDelay, UInt32 msResolution, MultimediaTimerCallback callback, ref UInt32 userCtx, UInt32 eventType);

    [DllImport("winmm.dll", SetLastError = true, EntryPoint = "timeKillEvent")]
    internal static extern void TimeKillEvent(UInt32 uTimerId);
}




high-resolution