आप C # कंसोल एप्लिकेशन में टाइमर कैसे जोड़ते हैं


132

बस यह - आप C # कंसोल एप्लिकेशन में टाइमर कैसे जोड़ सकते हैं? यह बहुत अच्छा होगा यदि आप कुछ उदाहरण कोडिंग की आपूर्ति कर सकते हैं।


16
सावधानी: यहां के जवाबों में एक बग है, टाइमर ऑब्जेक्ट को कचरा एकत्र करना है। टाइमर का संदर्भ स्थिर चर में संग्रहीत किया जाना चाहिए ताकि यह सुनिश्चित हो सके कि यह टिक रहा है।
हंस पसंत

@HansPassant आपको मेरे उत्तर में स्पष्ट कथन याद आ गया है: "यह हमेशा एक स्थिर (VB.NET में साझा) System.Threading का उपयोग करने के लिए अनुशंसित है। यदि आप एक Windows सेवा विकसित कर रहे हैं और समय-समय पर चलाने के लिए टाइमर की आवश्यकता होती है । यह आपके टाइमर ऑब्जेक्ट के संभवतः समय से पहले कचरा संग्रह से बच जाएगा। " यदि लोग एक यादृच्छिक उदाहरण की नकल करना चाहते हैं और इसका उपयोग आँख बंद करके करते हैं तो यह उनकी समस्या है।
ऐश

जवाबों:


120

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

हालाँकि, लूप का उपयोग करने की शैली कुछ कार्यक्षमता को हमेशा के लिए उपयोग करने के लिए बहुत सारे डिवाइस संसाधन लेती है और इसके बजाय हम गारबेज कलेक्टर का उपयोग कुछ ऐसा करने के लिए कर सकते हैं।

हम इस संशोधन को उसी पुस्तक सीएलआर वाया सी # थर्ड एड से देख सकते हैं।

using System;
using System.Threading;

public static class Program {

   public static void Main() {
      // Create a Timer object that knows to call our TimerCallback
      // method once every 2000 milliseconds.
      Timer t = new Timer(TimerCallback, null, 0, 2000);
      // Wait for the user to hit <Enter>
      Console.ReadLine();
   }

   private static void TimerCallback(Object o) {
      // Display the date/time when this method got called.
      Console.WriteLine("In TimerCallback: " + DateTime.Now);
      // Force a garbage collection to occur for this demo.
      GC.Collect();
   }
}

3
खालिद, यह बेहद मददगार था। धन्यवाद। कंसोल। ट्रेडलाइन () और GC.Collect बस वही था जो मुझे चाहिए था।
सेठ स्पीयरमैन

9
@ राल्फ विलगॉस, क्यों GC.Collect (); आवश्यक है?
Puchacz

2
@Puchacz मुझे कॉल करने का एक बिंदु नहीं दिखता है GC.Collect()। इकट्ठा करने के लिए कुछ भी नहीं है। यह समझ में आता है, अगर के GC.KeepAlive(t)बाद बुलाया गया थाConsole.ReadLine();
newprint

1
पहली कॉलबैक के बाद इसे समाप्त कर दिया गया
BadPiggie

1
@ खालिद अल हज़ामी "हालांकि, कुछ कार्यक्षमता को हमेशा के लिए करने के लिए लूप का उपयोग करने की शैली बहुत सारे उपकरण संसाधनों को लेती है और इसके बजाय हम गारबेज कलेक्टर का उपयोग कुछ ऐसा करने के लिए कर सकते हैं।" यह पूर्ण निरर्थक बकवास है। कचरा संग्रहकर्ता पूरी तरह अप्रासंगिक है। क्या आपने इसे एक किताब से कॉपी किया और यह नहीं समझा कि आप क्या कॉपी कर रहे थे?
ऐश

65

System.Threading.Timer वर्ग का उपयोग करें।

System.Windows.Forms.Timer मुख्य रूप से एक ही धागे में आमतौर पर विंडोज फॉर्म यूआई धागे में उपयोग के लिए डिज़ाइन किया गया है।

.NET फ्रेमवर्क के विकास में आरंभ में जोड़ा गया एक System.Timers वर्ग भी है। हालाँकि, यह आमतौर पर System.Threading.Timer वर्ग का उपयोग करने के लिए अनुशंसित है, क्योंकि यह सिर्फ System.Threading के आसपास एक आवरण है। वैसे भी।

यह भी हमेशा एक स्थिर (VB.NET में साझा) System.Threading.Timer का उपयोग करने के लिए अगर आप एक Windows सेवा विकसित कर रहे हैं और समय-समय पर चलाने के लिए एक टाइमर की आवश्यकता है की सिफारिश की है। यह संभवतः आपके टाइमर ऑब्जेक्ट के समय से पहले कचरा संग्रह से बच जाएगा।

यहाँ कंसोल एप्लिकेशन में टाइमर का एक उदाहरण दिया गया है:

using System; 
using System.Threading; 
public static class Program 
{ 
    public static void Main() 
    { 
       Console.WriteLine("Main thread: starting a timer"); 
       Timer t = new Timer(ComputeBoundOp, 5, 0, 2000); 
       Console.WriteLine("Main thread: Doing other work here...");
       Thread.Sleep(10000); // Simulating other work (10 seconds)
       t.Dispose(); // Cancel the timer now
    }
    // This method's signature must match the TimerCallback delegate
    private static void ComputeBoundOp(Object state) 
    { 
       // This method is executed by a thread pool thread 
       Console.WriteLine("In ComputeBoundOp: state={0}", state); 
       Thread.Sleep(1000); // Simulates other work (1 second)
       // When this method returns, the thread goes back 
       // to the pool and waits for another task 
    }
}

जेफ रिक्टर की पुस्तक CLR Via C # से। वैसे इस पुस्तक में अध्याय 23 में 3 प्रकार के टाइमर के पीछे तर्क का वर्णन है, अत्यधिक अनुशंसित है।


क्या आप वास्तविक कोडिंग पर थोड़ी अधिक जानकारी प्रदान कर सकते हैं?
जोहान ब्रेस्लर

क्या msdn से उदाहरण आपके लिए काम करता है? msdn.microsoft.com/en-us/library/system.threading.timer.aspx
एरिक टटलमैन

एरिक, मैंने इसे आज़माया नहीं है, लेकिन इसके साथ कोई समस्या होने पर यह असामान्य नहीं होगा। मुझे लगता है कि यह कुछ प्रकार के अंतर-थ्रेड सिंक्रोनाइज़ेशन करने की भी कोशिश कर रहा है, यह एक ऐसा क्षेत्र है जो सही होने के लिए मुश्किल हो सकता है। यदि आप इसे अपने डिजाइन से बचा सकते हैं, तो ऐसा करना हमेशा स्मार्ट होता है।
एश

1
ऐश - मैं निश्चित रूप से msdn उदाहरणों के बारे में सहमत हूं। मैं तुरंत सिंक्रोनाइज़ेशन कोड पर छूट नहीं दूंगा, लेकिन अगर टिमर खुद के धागे में चलता है, तो आप एक बहु-थ्रेडेड ऐप लिख रहे हैं और सिंक्रनाइज़ेशन से संबंधित मुद्दों के बारे में पता होना चाहिए।
एरिक टटलमैन

1
अगर कई तरीके हैं जो टाइमररबैक प्रतिनिधि हस्ताक्षर से मेल खाते हैं तो क्या होगा?
ओजकन

22

यहाँ एक सरल एक सेकंड टाइमर टिक बनाने के लिए कोड है:

  using System;
  using System.Threading;

  class TimerExample
  {
      static public void Tick(Object stateInfo)
      {
          Console.WriteLine("Tick: {0}", DateTime.Now.ToString("h:mm:ss"));
      }

      static void Main()
      {
          TimerCallback callback = new TimerCallback(Tick);

          Console.WriteLine("Creating timer: {0}\n", 
                             DateTime.Now.ToString("h:mm:ss"));

          // create a one second timer tick
          Timer stateTimer = new Timer(callback, null, 0, 1000);

          // loop here forever
          for (; ; )
          {
              // add a sleep for 100 mSec to reduce CPU usage
              Thread.Sleep(100);
          }
      }
  }

और यहाँ परिणामी आउटपुट है:

    c:\temp>timer.exe
    Creating timer: 5:22:40

    Tick: 5:22:40
    Tick: 5:22:41
    Tick: 5:22:42
    Tick: 5:22:43
    Tick: 5:22:44
    Tick: 5:22:45
    Tick: 5:22:46
    Tick: 5:22:47

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


7
के लिए ((?) {} 100% सीपीयू उपयोग का कारण बनता है।
सेठ स्पीयरमैन

1
क्या यह बिल्कुल स्पष्ट नहीं है यदि आपके पास लूप के लिए अनंत है तो इसका परिणाम 100% सीपीयू होगा। यह तय करने के लिए कि आपको बस एक नींद कॉल को लूप में जोड़ना होगा।
वेट

3
यह आश्चर्यजनक है कि कितने लोगों पर यह तय किया जाता है कि क्या लूप थोड़ी देर के लिए होना चाहिए और सीपीयू 100% पर क्यों जाता है। पेड़ों के लिए लकड़ी याद आती है के बारे में बात करो! अजीमुथ, मैं व्यक्तिगत रूप से जानना चाहूंगा कि एक समय (1) लूप के लिए अनंत से कितना अलग होगा? निश्चित रूप से सीएलआर कंपाइलर ऑप्टिमाइज़र लिखने वाले लोग सुनिश्चित करेंगे कि ये दोनों कोड निर्माण बिलकुल उसी सीएलआर कोड का निर्माण करें?
ब्लेक

1
एक कारण है कि जब (1) काम नहीं करेगा तो यह मान्य नहीं है c:: test.cs (21,20): त्रुटि CS0031: लगातार मान '1' को 'बूल' में परिवर्तित नहीं किया जा सकता है
ब्लेक

1
मेरी मशीन पर नहीं (win8.1, i5), केवल 20-30% के बारे में, आपके पास किस तरह का कंप्यूटर था? @SethSpearman
shinzou

17

चलो थोड़ा मज़ा है

using System;
using System.Timers;

namespace TimerExample
{
    class Program
    {
        static Timer timer = new Timer(1000);
        static int i = 10;

        static void Main(string[] args)
        {            
            timer.Elapsed+=timer_Elapsed;
            timer.Start(); Console.Read();
        }

        private static void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            i--;

            Console.Clear();
            Console.WriteLine("=================================================");
            Console.WriteLine("                  DEFUSE THE BOMB");
            Console.WriteLine(""); 
            Console.WriteLine("                Time Remaining:  " + i.ToString());
            Console.WriteLine("");        
            Console.WriteLine("=================================================");

            if (i == 0) 
            {
                Console.Clear();
                Console.WriteLine("");
                Console.WriteLine("==============================================");
                Console.WriteLine("         B O O O O O M M M M M ! ! ! !");
                Console.WriteLine("");
                Console.WriteLine("               G A M E  O V E R");
                Console.WriteLine("==============================================");

                timer.Close();
                timer.Dispose();
            }

            GC.Collect();
        }
    }
}

11

या Rx का उपयोग कर, छोटा और मीठा:

static void Main()
{
Observable.Interval(TimeSpan.FromSeconds(10)).Subscribe(t => Console.WriteLine("I am called... {0}", t));

for (; ; ) { }
}

1
सबसे अच्छा समाधान, वास्तव में!
दिमित्री लेडेंटसोव

8
बहुत ही अपठनीय और सर्वोत्तम अभ्यास के खिलाफ। यह बहुत अच्छा लग रहा है, लेकिन इसका उपयोग उत्पादन में नहीं किया जाना चाहिए क्योंकि कुछ पीपीएल wtf और स्वयं पू जाएगा।
पायोतर कुला

2
रिएक्टिव एक्सटेंशन्स (आरएक्स) 2 वर्षों से सक्रिय रूप से विकसित नहीं हुआ है। इसके अलावा उदाहरण बिना संदर्भ और भ्रम के हैं। आरेख या प्रवाह के उदाहरण जानने के लिए कम।
जेम्स बेली

4

यदि आप थोड़ा और नियंत्रण चाहते हैं, लेकिन संभवतः कम सटीकता और अधिक कोड / जटिलता चाहते हैं, तो आप अपने स्वयं के समय तंत्र का उपयोग भी कर सकते हैं, लेकिन मैं अभी भी एक टाइमर की सिफारिश करूंगा। यदि आपको वास्तविक टाइमिंग थ्रेड पर नियंत्रण रखने की आवश्यकता है, तो इसका उपयोग करें:

private void ThreadLoop(object callback)
{
    while(true)
    {
        ((Delegate) callback).DynamicInvoke(null);
        Thread.Sleep(5000);
    }
}

आपका टाइमिंग थ्रेड होगा (इसे फिर से शुरू करने पर रोकें और जो भी समय अंतराल पर आप चाहें) संशोधित करें।

और आप कर सकते हैं उपयोग / शुरू करने के लिए:

Thread t = new Thread(new ParameterizedThreadStart(ThreadLoop));

t.Start((Action)CallBack);

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

private void CallBack()
{
    //Do Something.
}

1
यदि मैं एक बैच की नौकरी को तब तक चलाना चाहता हूं, जब तक कि आपका सुझाव यहां सबसे अच्छा नहीं होगा?
जोहान ब्रेस्लर

1

आप अपना स्वयं का भी बना सकते हैं (यदि उपलब्ध विकल्पों से नाखुश हैं)।

अपने खुद के Timerकार्यान्वयन बनाने के लिए बहुत बुनियादी सामान है।

यह एक ऐसे अनुप्रयोग के लिए एक उदाहरण है जिसके लिए मेरे कोडबेस के बाकी हिस्सों के समान COM ऑब्जेक्ट की आवश्यकता होती है।

/// <summary>
/// Internal timer for window.setTimeout() and window.setInterval().
/// This is to ensure that async calls always run on the same thread.
/// </summary>
public class Timer : IDisposable {

    public void Tick()
    {
        if (Enabled && Environment.TickCount >= nextTick)
        {
            Callback.Invoke(this, null);
            nextTick = Environment.TickCount + Interval;
        }
    }

    private int nextTick = 0;

    public void Start()
    {
        this.Enabled = true;
        Interval = interval;
    }

    public void Stop()
    {
        this.Enabled = false;
    }

    public event EventHandler Callback;

    public bool Enabled = false;

    private int interval = 1000;

    public int Interval
    {
        get { return interval; }
        set { interval = value; nextTick = Environment.TickCount + interval; }
    }

    public void Dispose()
    {
        this.Callback = null;
        this.Stop();
    }

}

आप घटनाओं को इस प्रकार जोड़ सकते हैं:

Timer timer = new Timer();
timer.Callback += delegate
{
    if (once) { timer.Enabled = false; }
    Callback.execute(callbackId, args);
};
timer.Enabled = true;
timer.Interval = ms;
timer.Start();
Window.timers.Add(Environment.TickCount, timer);

यह सुनिश्चित करने के लिए कि टाइमर काम करता है आपको निम्न प्रकार से एक अंतहीन लूप बनाने की आवश्यकता है:

while (true) {
     // Create a new list in case a new timer
     // is added/removed during a callback.
     foreach (Timer timer in new List<Timer>(timers.Values))
     {
         timer.Tick();
     }
}

1

C # 5.0+ और .NET फ्रेमवर्क 4.5+ में आप async / प्रतीक्षा का उपयोग कर सकते हैं:

async void RunMethodEvery(Action method, double seconds)
{
    while (true)
    {
        await Task.Delay(TimeSpan.FromSeconds(seconds));
        method();
    }
 }

0

दस्तावेज़

ये लो :)

public static void Main()
   {
      SetTimer();

      Console.WriteLine("\nPress the Enter key to exit the application...\n");
      Console.WriteLine("The application started at {0:HH:mm:ss.fff}", DateTime.Now);
      Console.ReadLine();
      aTimer.Stop();
      aTimer.Dispose();

      Console.WriteLine("Terminating the application...");
   }

   private static void SetTimer()
   {
        // Create a timer with a two second interval.
        aTimer = new System.Timers.Timer(2000);
        // Hook up the Elapsed event for the timer. 
        aTimer.Elapsed += OnTimedEvent;
        aTimer.AutoReset = true;
        aTimer.Enabled = true;
    }

    private static void OnTimedEvent(Object source, ElapsedEventArgs e)
    {
        Console.WriteLine("The Elapsed event was raised at {0:HH:mm:ss.fff}",
                          e.SignalTime);
    }

0

मेरा सुझाव है कि आप Microsoft दिशानिर्देश ( https://docs.microsoft.com/en-us/dotnet/api/system.timers.timer.interval?view=netcore-3.1 ) का अनुसरण कर रहे हैं ।

मैं पहली बार उपयोग करने की कोशिश System.Threading;के साथ

var myTimer = new Timer((e) =>
{
   // Code
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));

लेकिन यह लगातार ~ 20 मिनट के बाद बंद हो गया।

इसके साथ, मैंने समाधान स्थापित करने का प्रयास किया

GC.KeepAlive(myTimer)

या

for (; ; ) { }
}

लेकिन उन्होंने मेरे मामले में काम नहीं किया।

Microsoft प्रलेखन के बाद, इसने पूरी तरह से काम किया:

using System;
using System.Timers;

public class Example
{
    private static Timer aTimer;

    public static void Main()
    {
        // Create a timer and set a two second interval.
        aTimer = new System.Timers.Timer();
        aTimer.Interval = 2000;

        // Hook up the Elapsed event for the timer. 
        aTimer.Elapsed += OnTimedEvent;

        // Have the timer fire repeated events (true is the default)
        aTimer.AutoReset = true;

        // Start the timer
        aTimer.Enabled = true;

        Console.WriteLine("Press the Enter key to exit the program at any time... ");
        Console.ReadLine();
    }

    private static void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
    {
        Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
    }
}
// The example displays output like the following: 
//       Press the Enter key to exit the program at any time... 
//       The Elapsed event was raised at 5/20/2015 8:48:58 PM 
//       The Elapsed event was raised at 5/20/2015 8:49:00 PM 
//       The Elapsed event was raised at 5/20/2015 8:49:02 PM 
//       The Elapsed event was raised at 5/20/2015 8:49:04 PM 
//       The Elapsed event was raised at 5/20/2015 8:49:06 PM 
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.