27

I want to execute some code on each second. The code I am using now is:

Task.Run((Action)ExecuteSomething);

And ExecuteSomething() is defined as below:

 private void ExecuteSomething()
        {
            Task.Delay(1000).ContinueWith(
               t =>
               {
                   //Do something.

                   ExecuteSomething();
               });
        }

Does this method block a thread? Or should I use Timer class in C#? And it seems Timer also dedicates a separate thread for execution (?)

Community
  • 1
  • 1
Sharun
  • 3,022
  • 6
  • 30
  • 59

4 Answers4

36

Task.Delay uses Timer internally

With Task.Delay you can make your code a little-bid clearer than with Timer. And using async-await will not block the current thread (UI usually).

public async Task ExecuteEverySecond(Action execute)
{
    while(true)
    {
        execute();
        await Task.Delay(1000);
    }
}

From source code: Task.Delay

// on line 5893
// ... and create our timer and make sure that it stays rooted.
if (millisecondsDelay != Timeout.Infinite) // no need to create the timer if it's an infinite timeout
{
    promise.Timer = new Timer(state => ((DelayPromise)state).Complete(), promise, millisecondsDelay, Timeout.Infinite);
    promise.Timer.KeepRootedWhileScheduled();
}

// ...
Jazimov
  • 12,626
  • 9
  • 52
  • 59
Fabio
  • 31,528
  • 4
  • 33
  • 72
9

Microsoft's Reactive Framework is ideal for this. Just NuGet "System.Reactive" to get the bits. Then you can do this:

IDisposable subscription =
    Observable
        .Interval(TimeSpan.FromSeconds(1.0))
        .Subscribe(x => execute());

When you want to stop the subscription just call subscription.Dispose(). On top of this the Reactive Framework can offer far more power than Tasks or basic Timers.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • 2
    Does using Rx in my case have any specific advantages than using Task.Delay ? Just want to know is it worth to include the package just for this purpose. Upvoted anyway. – Sharun Feb 14 '17 at 08:08
  • 1
    @Sharun - Rx has as much power as LINQ and then some. From what you've described there's nothing more that you need, but I suspect you'd actually benefit from what Rx offers. Can you describe more about what you're trying to do? – Enigmativity Feb 14 '17 at 08:46
2

Can you use Task.Delay as a timer? It depends on whether you need to be waiting an exact interval, or whether you just need to wait a specified interval AFTER other work is done.

In other words, I have used a Timer many times in the past as part of a service that fetches or pushes data for the purposes of synchronization. The problem is that if you fetch data every 60 seconds, but there is a slow in the database and your retrieval takes over 60 seconds. Now you have a problem as you are going to be fetching the same data twice. So then you update the process so that you stop the timer until it finishes, and then start the timer again. This works fine, but using Task.Delay does this work for you.

So if you are just needing to Delay for a bit of time between executions, then Task.Delay works perfectly.

Greg Gum
  • 33,478
  • 39
  • 162
  • 233
  • I have used System.Threading.Timer with Change(delay, -1) and restart timer after fetching data. So it cannot be twice, but you have to restart timer at any time. Specially after exceptions. – Arci Feb 09 '23 at 15:47
0
static class Helper
{
    public async static Task ExecuteInterval(Action execute, int millisecond, IWorker worker)
    {
        while (worker.Worked)
        {
            execute();

            await Task.Delay(millisecond);
        }
    }
}


interface IWorker
{
    bool Worked { get; }
}
nim
  • 357
  • 1
  • 5
  • 16
  • Beware that if `execute`'s running time is even somewhat significant compared to the delay, this will drift, i.e. not honor a periodic interval. – Timo Jun 23 '21 at 08:44
  • 2
    @Timo people can consider `PeriodicTimer` in .NET 6 to resolve this drift issue. – prospector Feb 14 '22 at 00:50