<返回更多

.NET 6 新特性 PeriodicTimer

2021-12-06    IT狂人日记
加入收藏

Intro

.NET 6 中引入了一个新的 Timer ——
System.Threading.PeriodicTimer,和之前的几个 Timer 相比一个最大的区别就是,新的 PeriodicTimer 的事件处理可以比较方便地使用异步方式,消除了使用 callback 的机制,减少了使用的复杂度。

Sample

来看一个使用示例:

using var cts = new CancellationTokenSource();
Console.CancelKeyPress += (sender, e) =>
{
    e.Cancel = true;
    cts.Cancel();
};

using var timer = new PeriodicTimer(TimeSpan.FromSeconds(3));
try
{
    while (await timer.WaitForNextTickAsync(cts.Token))
    {
        Console.WriteLine($"Timed event triggered({DateTime.Now:HH:mm:ss})");
    }
}
catch (OperationCanceledException)
{
    Console.WriteLine("Operation cancelled");
}

通常 PeriodicTimer 可以结合 CancellationToken 一起使用,和 CancellationToken 一起用的时候需要注意,如果 cancellationToken 被取消的时候会抛出一个
OperationCanceledException 需要考虑自己处理异常

除此之外如果 PeriodicTimer 被 Dispose,这个 timer 就相当于是失效的,并且无法重新恢复,来看下面这个示例:

var timer1 = new PeriodicTimer(TimeSpan.FromSeconds(2));
timer1.Dispose();
if (await timer1.WaitForNextTickAsync())
{
    Console.WriteLine("Timer1 event triggered");
}

上面这样的一段代码,在 WaitForNextTickAsync 之前就已经调用了 Dispose(),此时 WaitForNextTickAsync 方法会始终返回 false ,所以 Console.WriteLine 的逻辑也不会被执行

我们之前会尝试使用 Timer 来做一些后台任务,可以改造成使用新的 PeriodicTimer 来实现,小示例如下:

public abstract class TimerScheduledService : BackgroundService
{
    private readonly PeriodicTimer _timer;
    private readonly TimeSpan _period;
    protected readonly ILogger Logger;

    protected TimerScheduledService(TimeSpan period, ILogger logger)
    {
        Logger = logger;
        _period = period;
        _timer = new PeriodicTimer(_period);
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        try
        {
            while (await _timer.WaitForNextTickAsync(stoppingToken))
            {
                try
                {
                    Logger.LogInformation("Begin execute service");
                    await ExecuteInternal(stoppingToken);
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex, "Execute exception");
                }
                finally
                {
                    Logger.LogInformation("Execute finished");
                }
            }
        }
        catch (OperationCanceledException operationCancelledException)
        {
            Logger.LogWarning(operationCancelledException, "service stopped");
        }
    }

    protected abstract Task ExecuteInternal(CancellationToken stoppingToken);

    public override Task StopAsync(CancellationToken cancellationToken)
    {
        Logger.LogInformation("Service is stopping.");
        _timer.Dispose();
        return base.StopAsync(cancellationToken);
    }
}

实现示例如下:

public class TimedHealthCheckService : TimerScheduledService
{
    public TimedHealthCheckService(ILogger<TimedHealthCheckService> logger) : base(TimeSpan.FromSeconds(5), logger)
    {
    }

    protected override Task ExecuteInternal(CancellationToken stoppingToken)
    {
        Logger.LogInformation("Executing...");
        return Task.CompletedTask;
    }
}

运行输出如下:

.NET 6 新特性 PeriodicTimer

 

More

新的 PeriodicTimer 相比之前的几个 Timer 来说,有下面几个特点

最后来做一个题目,把第一个示例改造一下,最终代码如下:

using var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(30));
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(3));
try
{
    while (await timer.WaitForNextTickAsync(cts.Token))
    {
        await Task.Delay(5000);
        Console.WriteLine($"Timed event triggered({DateTime.Now:HH:mm:ss})");
    }
}
catch (OperationCanceledException)
{
    Console.WriteLine("Operation cancelled");
}

猜一下输出结果是什么,Timed event triggered 会输出几次

.NET 6 新特性 PeriodicTimer

 

References

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>