我用
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中。更改本机PeriodicTimer
的Period
将产生与上述UpdateablePeriodicTimer
实现不同的行为。更改PeriodicTimer.Period
将根据新的周期重新调度当前活动的WaitForNextTickAsync
。相反,更改上述UpdateablePeriodicTimer.Period
不会影响当前激活的WaitForNextTickAsync
。