C# System.Timers.Timer有时会停止,然后在一段时间后恢复

C# System.Timers.Timer有时会停止,然后在一段时间后恢复,c#,.net,multithreading,.net-core,timer,C#,.net,Multithreading,.net Core,Timer,让我们创建一个类,每5秒刷新Redis中的一个键。(我们称之为“死人开关”)。 问题是,每隔几天,它只会在短时间内(从秒到1-2分钟)停止发出经过的事件 使用系统; 使用系统计时器; 使用Microsoft.Extensions.Logging; 使用StackExchange.Redis; 名称空间我的 { 公共类测试:IDisposable { 专用只读ILogger\u记录器; 私有只读IDatabase\u redis; 专用只读系统.Timers.Timer\u Timer; 公共测试

让我们创建一个类,每5秒刷新Redis中的一个键。(我们称之为“死人开关”)。 问题是,每隔几天,它只会在短时间内(从秒到1-2分钟)停止发出经过的事件

使用系统;
使用系统计时器;
使用Microsoft.Extensions.Logging;
使用StackExchange.Redis;
名称空间我的
{
公共类测试:IDisposable
{
专用只读ILogger\u记录器;
私有只读IDatabase\u redis;
专用只读系统.Timers.Timer\u Timer;
公共测试(ILogger记录器,IDatabase redis)
{
_记录器=记录器;
_redis=redis;
_定时器=新定时器{Interval=5000};
_计时器。已用+=节拍;
_timer.Start();
}
私有无效节拍(对象发送器,ElapsedEventArgs e)
{
_logger.LogInformation(“推送DMS”);
_redis.StringSet(“1234”,“OK”,TimeSpan.FromSeconds(10),When.Always,CommandFlags.FireAndForget);
_logger.LogInformation(“DMS推送”);
}
公共空间处置()
{
控制台。写入线(“处置”);
_计时器?.Dispose();
}
}
}
日志:

。。。
[08:08:40 INF]正在推DMS。
[08:08:40 INF]DMS已按下。
[08:08:45 INF]正在推DMS。
[08:08:45 INF]DMS已按下。
[08:08:50 INF]正在推DMS。
[08:08:50 INF]DMS已按下。

[08:09:17 INF]正在推DMS#你说这是一个更大的应用程序的一部分;当这些间隙出现时,您是否记录了应用程序正在执行的操作?我的直觉是说,
计时器的线程有阻塞。可能是系统CPU过载,计时器无法运行,或者是发生了长时间的垃圾收集(在此期间所有线程都暂停)。“EF等待DB更新时会出现间隙”-您没有回答您的问题吗?听起来你的数据库由于某种原因需要一段时间才能响应,而应用程序正在等待响应。您是否可能存在争用(多个应用程序实例试图更新同一个表)?您是否考虑过使用专用线程发送周期性的
节拍
System.Timers.Timer
使用
ThreadPool
中的线程来调用事件处理程序,因此它不如专用线程可靠,因为它取决于
ThreadPool
的可用性。我会添加GC开始/结束事件的日志记录,以排除这种可能性。我同意上面的Theodor尝试使用专用线程,以排除线程池的问题(以防万一);当这些间隙出现时,您是否记录了应用程序正在执行的操作?我的直觉是说,
计时器的线程有阻塞。可能是系统CPU过载,计时器无法运行,或者是发生了长时间的垃圾收集(在此期间所有线程都暂停)。“EF等待DB更新时会出现间隙”-您没有回答您的问题吗?听起来你的数据库由于某种原因需要一段时间才能响应,而应用程序正在等待响应。您是否可能存在争用(多个应用程序实例试图更新同一个表)?您是否考虑过使用专用线程发送周期性的
节拍
System.Timers.Timer
使用
ThreadPool
中的线程来调用事件处理程序,因此它不如专用线程可靠,因为它取决于
ThreadPool
的可用性。我会添加GC开始/结束事件的日志记录,以排除这种可能性。我同意上面的Theodor尝试使用专用线程,以排除线程池的问题(以防万一)。