Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can the Elapsed callback of a System.Timers.Timer be async?

Is it possible (or even reasonable) to make the callback of a System.Timers.Timer an async method? Something like:

var timer = new System.Timers.Timer
{
   Interval = TimeSpan.FromSeconds(30).TotalMilliseconds,
   AutoReset = true
};
timer.Elapsed += async (sender, e) => { /* await something */ };
timer.Start();

It compiles (obviously a good place to start), but I'm not sure I understand the consequences. Will the timer await the callback before resetting the timer?

like image 595
David Rubin Avatar asked Jan 27 '15 18:01

David Rubin


People also ask

What does timer elapsed mean?

Elapsed time is the amount of time that passes from the start of an event to its finish. In simplest terms, elapsed time is how much time goes by from one time (say 3:35pm) to another (6:20pm).

Does system timers timer run in a separate thread?

Yes, they run in a different thread.

How do I stop a timer elapsed event?

It would have already queued before you have called Stop method. It will fire at the elapsed time. To avoid this happening set Timer. AutoReset to false and start the timer back in the elapsed handler if you need one.

What is timer elapsed in C#?

Elapsed event every two seconds (2000 milliseconds), sets up an event handler for the event, and starts the timer. The event handler displays the value of the ElapsedEventArgs. SignalTime property each time it is raised.


2 Answers

Will the timer await the callback before resetting the timer?

No. There's nothing it could await, because the signature of ElapsedEventHandler has a void return type.

In other words, your code is equivalent to:

var timer = new System.Timers.Timer { ... };
timer.Elapsed += Foo;
timer.Start();

...
private async void Foo()
{
    ...
}

Whether that's acceptable for you or not will depend on your context. In general, having async void methods or anonymous functions makes them harder to test and reuse - but the ability was precisely given for the sake of event handlers... You should consider how errors will be propagated though.

like image 191
Jon Skeet Avatar answered Sep 19 '22 14:09

Jon Skeet


The title of the question is specifically about Timers, but if we look at it as "How to call an async method after some time?" then you could do it without using a timer.

var task2 = Task.Run(async () => {
    while (true)
    {
        try
        {
            await MyMethod2();
        } catch
        {
            //super easy error handling
        }
        await Task.Delay(TimeSpan.FromSeconds(5));
    }
});

...

public async Task MyMethod2()
{
    //async work here
}

Please note however that this will have different timing (timer will be called at an interval, the code above will be called every (run time + sleep_time), but even if MyMethod2 takes a long time it it won't be called twice. Having said that, you can calculate how long to await for to run 'every x minutes'.

like image 34
tymtam Avatar answered Sep 18 '22 14:09

tymtam