BackgroundService中具有动态周期的PeriodicTimer



我用

using PeriodicTimer timer = new(_period);
while (!stoppingToken.IsCancellationRequested
&& await timer.WaitForNextTickAsync(stoppingToken))
{
await DoWork();
}

是否有动态设置_period的方法?也就是说,以数据库的那段时间为例。

不允许,Periodic Timer实例化后不允许更改period

您可以使用从其他地方获得的值构造原始的或新的不同的Periodic Timer,但是,请确保Dispose实例,以便可以释放所需的资源。

如果你需要一个可变延迟,你可以使用Task.Delay代替。

下面是一个自定义的UpdateablePeriodicTimer类,它本质上是一个具有可变Period属性的PeriodicTimer:

public class UpdateablePeriodicTimer : IDisposable
{
private readonly object _locker = new();
private PeriodicTimer _timer; // Becomes null when disposed
private PeriodicTimer _newTimer;
private TimeSpan _period;
private bool _waiting;
public UpdateablePeriodicTimer(TimeSpan period)
{
_timer = new(period);
_period = period;
}
public TimeSpan Period
{
get { lock (_locker) return _period; }
set
{
PeriodicTimer timerToDispose;
lock (_locker)
{
if (_timer is null) throw new ObjectDisposedException(null,
$"The {nameof(UpdateablePeriodicTimer)} has been disposed.");
if (_waiting)
{
timerToDispose = _newTimer;
_newTimer = new(value);
}
else
{
timerToDispose = _timer;
_timer = new(value);
}
_period = value;
}
timerToDispose?.Dispose();
}
}
public async ValueTask<bool> WaitForNextTickAsync(
CancellationToken cancellationToken = default)
{
cancellationToken.ThrowIfCancellationRequested();
ValueTask<bool> waitTask;
lock (_locker)
{
if (_timer is null) return false; // Disposed
if (_waiting) throw new InvalidOperationException();
waitTask = _timer.WaitForNextTickAsync(cancellationToken);
_waiting = true;
}
try { return await waitTask.ConfigureAwait(false); }
finally
{
PeriodicTimer timerToDispose = null;
lock (_locker)
{
_waiting = false;
if (_timer is not null && _newTimer is not null)
{
timerToDispose = _timer;
_timer = _newTimer;
_newTimer = null;
}
}
timerToDispose?.Dispose();
}
}
public void Dispose()
{
PeriodicTimer timerToDispose;
lock (_locker)
{
if (_timer is null) return; // Disposed
timerToDispose = _timer;
_timer = null;
_newTimer?.Dispose();
}
timerToDispose.Dispose();
}
}

更改Period立即启动一个新的PeriodicTimer,当活动WaitForNextTickAsync完成时,它将与当前的PeriodicTimer交换,或者如果没有活动操作,则立即启动。

在线演示。

UpdateablePeriodicTimer类是线程安全的

在原生PeriodicTimer中添加Period属性的GitHub提案已被批准,并已合并实现。所以它很可能会被包含在。net 8中。更改本机PeriodicTimerPeriod将产生与上述UpdateablePeriodicTimer实现不同的行为。更改PeriodicTimer.Period将根据新的周期重新调度当前活动的WaitForNextTickAsync。相反,更改上述UpdateablePeriodicTimer.Period不会影响当前激活的WaitForNextTickAsync

最新更新