我有一项服务,用于订阅对存储库的更新。 收到更新消息后,该服务需要从存储库中重新加载一些数据。
但是,可以在短时间内接收到许多更新消息。因此,我想创建一个缓冲区/时间窗口,这意味着在到达许多更新消息的那段时间内,只会发生一次重新加载。
我创建了一个非常粗糙的轮廓:
class TestService
{
private Timer scheduledReloadTimer;
public void AttemptReload()
{
if (scheduledReloadTimer == null)
{
Console.WriteLine("Scheduling reload...");
scheduledReloadTimer = new Timer(Reload, null, 10000, Timeout.Infinite);
}
else
{
Console.WriteLine("Reload already scheduled for this period...");
}
}
private void Reload(object stateInfo)
{
scheduledReloadTimer.Dispose();
scheduledReloadTimer = null;
Console.WriteLine("Doing reload..");
}
}
在Timer上使用空检查是否足够好,以查看是否已安排重新加载?
我正确放置了计时器吗?
这里还有其他我想念的东西吗?
我看到了另一个stackoverflow答案,建议使用Reactive Extensions实现此目的:https://stackoverflow.com/a/42887221/67357,但这是矫over过正吗?
答案 0 :(得分:1)
您在这里确实存在潜在的线程安全问题。一种快速的解决方案是在代码的关键部分周围创建线程锁定范围,以确保在检查/创建和设置计时器变量时,没有其他线程可以进入并并行启动同一进程:
class TestService
{
private Timer scheduledReloadTimer;
private object timerLock = new object();
public void AttemptReload()
{
lock (timerLock)
{
if (scheduledReloadTimer == null)
{
Console.WriteLine("Scheduling reload...");
scheduledReloadTimer = new Timer(Reload, null, 10000, Timeout.Infinite);
}
else
{
Console.WriteLine("Reload already scheduled for this period...");
}
}
}
private void Reload(object stateInfo)
{
lock (timerLock)
{
scheduledReloadTimer.Dispose();
scheduledReloadTimer = null;
}
Console.WriteLine("Doing reload..");
}
}
响应式扩展 是解决此节流问题的好方法-因为已经为您编写了代码。
另一种方法可能是修改AttemptReload调用,以简单地重置计时器上的间隔(如果reloadTimer!= null),实质上是在以后每次对AttemptReload的调用中都推迟计时器事件的调用。
这样,在最后一次调用AttemptReload + 10,000毫秒之后,计时器肯定不会启动。