写点什么

.NET 6 新东西 --PeriodicTimer

作者:喵叔
  • 2021 年 12 月 05 日
  • 本文字数:1755 字

    阅读完需:约 6 分钟

在.NET 6 中引入了新 Timer:System.Threading.PeriodicTimer,它和之前的 Timer 相比,最大的区别就是新的 PeriodicTimer 事件处理可以方便地使用异步,消除使用 callback 机制减少使用复杂度。讲解 PeriodicTimer 之前我们先来看以下该怎么使用它:


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($"触发事件({DateTime.Now:HH:mm:ss})"); }}catch (OperationCanceledException e){ Console.WriteLine("出现异常,运行停止"+e.Message);}
复制代码


一般来说 PeriodicTimer 会结合 CancellationToken 来使用,需要注意的是当 CancellationToken 被取消时会抛出 OperationCanceledException 异常,因此需要手动处理异常。另外当 PeriodicTimer 被 Dispose 掉时,这个 timer 就失效且无法恢复,我们来看下面这个示例:


var timer1 = new PeriodicTimer(TimeSpan.FromSeconds(10));timer1.Dispose();if (await timer1.WaitForNextTickAsync()){    Console.WriteLine("事件执行");}
复制代码


上面的代码中在 WaitForNextTickAsync 之前就已经调用了 Dispose(),这时 WaitForNextTickAsync 方法就只能返回 false,因此后续的代码将不会被执行。在以前的.NET 版本中我们会使用 Timer 来做后台任务,那么在.NET6 中我们同样可以这么做,官方示例代码如下:


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; }}
复制代码

总结

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


  1. 没有 callback 来绑定事件;

  2. 不会发生重入,只允许有一个消费者,不允许同一个 PeriodicTimer 在不同的地方同时 WaitForNextTickAsync,不需要自己做排他锁来实现不能重入;

  3. 异步化。之前的 timer 的 callback 都是同步的,使用新 timer 可以使用异步方法,避免了编写 Sync over Async 代码;

  4. Dispose 之后,实例就无法使用,并且 WaitForNextTickAsync 始终返回 false。

用户头像

喵叔

关注

还未添加个人签名 2020.01.14 加入

还未添加个人简介

评论

发布
暂无评论
.NET 6新东西--PeriodicTimer