0

So I have a method that has to run every 30 seconds for upto 2 hours.

My code is:

private void btnJSON_Click(object sender, RoutedEventArgs e)
{
    Task.Factory.StartNew(() =>
    {
        //Timing Logic
        var geTimerDelay = 2;
        Stopwatch s = new Stopwatch();
        s.Start();
        while (s.Elapsed < TimeSpan.FromHours(geTimerDelay))
        {

            Stopwatch s30 = new Stopwatch();
            s30.Start();
            while (s.Elapsed < TimeSpan.FromSeconds(30))
            {
                //Method To Run
            }
            s30.Stop();
        }
        s.Stop();
    });
}

Am I doing it correctly (that is achieving the time-gap as mentioned) or is there a correct and/or more time - precise way to do it?

I need to know because I am access data from specific urls and sometimes I am getting null values, maybe due to too frequent access.

Thanks.

EDIT: This gave me an idea of not using a timer, for no specific reason.

user3378165
  • 6,546
  • 17
  • 62
  • 101
Jishan
  • 1,654
  • 4
  • 28
  • 62

3 Answers3

2

If you're going to use StopWatch then you need to do the following to actually have it wait 30 seconds between runs.

private void btnJSON_Click(object sender, RoutedEventArgs e)
{
    Task.Factory.StartNew(() =>
    {
        //Timing Logic
        var geTimerDelay = 2;
        Stopwatch s = new Stopwatch();
        s.Start();
        while (s.Elapsed < TimeSpan.FromHours(geTimerDelay))
        {
            Stopwatch s30 = new Stopwatch();
            s30.Start();
            //Method to run
            while (s.Elapsed < TimeSpan.FromSeconds(30))
            {
            }
            s30.Stop();
        }
        s.Stop();
    });
}

But you could just replace the internal StopWatch with a call to Thread.Sleep and avoid spiking the CPU.

private void btnJSON_Click(object sender, RoutedEventArgs e)
{
    Task.Factory.StartNew(() =>
    {
        //Timing Logic
        var geTimerDelay = 2;
        Stopwatch s = new Stopwatch();
        s.Start();
        while (s.Elapsed < TimeSpan.FromHours(geTimerDelay))
        {
            //Method to run
            Thread.Sleep(TimeSpan.FromSeconds(30));
        }
        s.Stop();
    });
}

Note that the second one puts a 30 second gap between runs. Meaning that the time it takes for your method to run is not included in the time between runs unlike the first one.

juharr
  • 31,741
  • 4
  • 58
  • 93
1

This gave me an idea of not using a timer, for no specific reason.

Timer is perfectly valid for this use case. The issue in the linked question was the precision of the stopwatch versus timer. You don't need that level of precision (I'm assuming) so there's nothing wrong with using a Timer.

Since you claim to be "accessing data from specific URLs", the variance in latency probably negates any improvement in precision by using Stopwatch.

I would instead focus on figuring out why you are getting null values, and decide what to to about it.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • Seems my logic isn't correct. I will need nested timers. – Jishan Jun 15 '16 at 19:34
  • 1
    You mean for the "`N` hours" part? you could, or just use a static `DateTime` value to know when you started. Precision is even less of a concern when you're dealing with a magnitude of hours. – D Stanley Jun 15 '16 at 19:37
  • I agree that a timer is the better choice than a sleep loop. However, I would strongly suggest *not* relying on `DateTime` to count elapsed time. If he just happens to start this code at 1:00 AM on the morning of a Daylight Saving Time change, then he can end up with the timer running for an hour longer than it should, or an hour shorter than it should. Or, if the user changes the time. Better to use a `StopWatch` to count elapsed time. – Jim Mischel Jun 15 '16 at 20:11
1
private int x = 0;
public Form1 ()
{
    InitializeComponent();
}

private void button1_Click ( object sender, EventArgs e )
{
    InitTimer();
}

private void timer1_Tick ( object sender, EventArgs e )
{
    bool s = IsFinished();
    if (s == true)
        textBox1.Text = "true";
}

private void InitTimer ()
{
    timer1 = new Timer();
    timer1.Tick += new EventHandler(timer1_Tick);
    timer1.Interval = 3000; //30000 is 30 seconds
    timer1.Start();
}
private bool IsFinished ()
{
    if (++x == 2) //1 min
    {
        timer1.Stop();
        return true;
    }
    else return false;
}

This is a real quick method of running your function or method a bunch of times controlled by a timer and a count. From How do I measure how long a function is running? , I would say that using a stopwatch is probably more precise and efficient than my dirty counter, but honestly the timing difference between stopwatch and timer is negligible at best unless you need better than milliseconds timing difference.

Community
  • 1
  • 1
Adam
  • 2,422
  • 18
  • 29
  • Your code has a bug. The `Interval` is set to 3 seconds rather than 30 seconds. – Jim Mischel Jun 15 '16 at 20:20
  • Read the comment next to the interval statement. No bug at all. – Adam Jun 21 '16 at 11:42
  • Well, okay. But then the comment in `IsFinished` is incorrect. As written, the timer will run for 6 seconds, not one minute. – Jim Mischel Jun 21 '16 at 13:54
  • For God sakes, it was a small program written to do what he wanted. I wrote it so it would do it for 3 second intervals rather than 30, notice the comment for 30 seconds like he wanted. Also notice the comment with `//1 min` written there. That is where he would make his change if he wanted to change it. There is absolutely nothing wrong with my answer. – Adam Jun 21 '16 at 15:43