Sharun
Sharun

Reputation: 3082

Can I use Task.Delay as a timer?

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 (?)

Upvotes: 29

Views: 18524

Answers (4)

Greg Gum
Greg Gum

Reputation: 37905

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.

Upvotes: 3

Fabio
Fabio

Reputation: 32445

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();
}

// ...

Upvotes: 39

nim
nim

Reputation: 328

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; }
}

Upvotes: 0

Enigmativity
Enigmativity

Reputation: 117047

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.

Upvotes: 9

Related Questions