.NET 6 新特性 PeriodicTimer
.NET 6 新特性 PeriodicTimer
Intro
.NET 6 中引入了一個(gè)新的 Timer —— ?System.Threading.PeriodicTimer,和之前的幾個(gè) Timer 相比一個(gè)最大的區(qū)別就是,新的 PeriodicTimer 的事件處理可以比較方便地使用異步方式,消除了使用 callback 的機(jī)制,減少了使用的復(fù)雜度。
Sample
來看一個(gè)使用示例:
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 可以結(jié)合 CancellationToken 一起使用,和 CancellationToken 一起用的時(shí)候需要注意,如果 cancellationToken 被取消的時(shí)候會(huì)拋出一個(gè) OperationCanceledException 需要考慮自己處理異常
除此之外如果 PeriodicTimer 被 Dispose,這個(gè) timer 就相當(dāng)于是失效的,并且無(wú)法重新恢復(fù),來看下面這個(gè)示例:
var?timer1?=?new?PeriodicTimer(TimeSpan.FromSeconds(2)); timer1.Dispose(); if?(await?timer1.WaitForNextTickAsync()) {Console.WriteLine("Timer1?event?triggered"); }上面這樣的一段代碼,在 WaitForNextTickAsync 之前就已經(jīng)調(diào)用了 Dispose(),此時(shí) WaitForNextTickAsync 方法會(huì)始終返回 false ,所以 Console.WriteLine 的邏輯也不會(huì)被執(zhí)行
我們之前會(huì)嘗試使用 Timer 來做一些后臺(tái)任務(wù),可以改造成使用新的 PeriodicTimer 來實(shí)現(xiàn),小示例如下:
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);} }實(shí)現(xiàn)示例如下:
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;} }運(yùn)行輸出如下:
logging outputMore
新的 PeriodicTimer 相比之前的幾個(gè) Timer 來說,有下面幾個(gè)特點(diǎn)
沒有 callback 來綁定事件
不會(huì)發(fā)生重入,只允許有一個(gè)消費(fèi)者,不允許同一個(gè) PeriodicTimer 在不同的地方同時(shí) WaitForNextTickAsync,不需要自己做排他鎖來實(shí)現(xiàn)不能重入
異步化,之前的幾個(gè) timer 的 callback 都是同步的,使用新的 timer 我們可以更好的使用異步方法,避免寫 Sync over Async 之類的代碼
Dispose() 之后,該實(shí)例就無(wú)法再使用,WaitForNextTickAsync 始終返回 false
最后來做一個(gè)題目,把第一個(gè)示例改造一下,最終代碼如下:
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"); }猜一下輸出結(jié)果是什么,Timed event triggered 會(huì)輸出幾次
References
https://www.ilkayilknur.com/a-new-modern-timer-api-in-dotnet-6-periodictimer
https://docs.microsoft.com/en-us/dotnet/api/system.threading.periodictimer?view=net-6.0
https://github.com/dotnet/runtime/blob/v6.0.0/src/libraries/System.Private.CoreLib/src/System/Threading/PeriodicTimer.cs
https://github.com/dotnet/runtime/issues/31525
https://github.com/WeihanLi/SamplesInPractice/blob/master/net6sample/PeriodicTimerSample/Program.cs
https://github.com/OpenReservation/ReservationServer/blob/dev/OpenReservation.Helper/Services/CronScheduleServiceBase.cs#L91
總結(jié)
以上是生活随笔為你收集整理的.NET 6 新特性 PeriodicTimer的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: EasyNetQ操作RabbitMQ
- 下一篇: 当.NET遇到机器学习