运行 使用 System.Threading 在 C# 中同时使用多个计时器
Running multiple timers simultaneously in C# using System.Threading
我有用于从网络位置提取报告的服务。要求是每 5 分钟我需要调出报告 1,每 10 分钟报告 2,每 3 小时报告 3、4、5。因此,我在一个单独的 worker class 的方法内创建了一个计时器,我在其中使用了 System.Threading.Timer 的 5 个实例。报告正在被撤回,但顺序不正确。我怎样才能 运行 计时器使报告可以按特定顺序提取或使用 1 个计时器安排以特定方式提取报告?
这是我到目前为止所做的:
private async void pullReports()
{
try
{
await _logger.Info($"Start Report Monitoring");
Timer timer = new Timer
(
async e => await Service.ReportMonitoring(reportNum: 1),
null,
TimeSpan.Zero,
TimeSpan.FromMinutes(5)
);
Timer timer2 = new Timer
(
async e => await Service.ReportMonitoring(reportNum: 2),
null,
TimeSpan.Zero,
TimeSpan.FromMinutes(10)
);
Timer timer3 = new Timer
(
async e => await Service.ReportMonitoring(reportNum: 3),
null,
TimeSpan.Zero,
TimeSpan.FromHours(3)
);
Timer timer4 = new Timer
(
async e => await Service.ReportMonitoring(reportNum: 4),
null,
TimeSpan.Zero,
TimeSpan.FromHours(3)
);
Timer timer5 = new Timer
(
async e => await Service.ReportMonitoring(reportNum: 5),
null,
TimeSpan.Zero,
TimeSpan.FromHours(3)
);
}
catch (Exception ex)
{
await _logger.Error($"Start Report Monitoring exception: {ex}");
}
}
感谢任何类型的代码改进。我认为因为我的方法 Service.ReportMonitoring() 是异步的,所以这就是扰乱收集顺序的原因。但我不确定。
ReportNum的代码如下:
private static Task<Stream> ReportMonitoring(int repnum)
{
string _urlDataFormat = "https://{0}/cgi-bin/CGILink?cmd=vtranssetz&period=2&reptnum={1}";
string dataUrl = string.Format(_urlDataFormat, <serverIP>, repnum);
return HttpService.ExecuteGetStreamAsync(dataUrl);
}
如果报告的顺序很重要(因此数字较大的应该始终排在数字较小的之后),您应该这样做:
var counter = 0L;
Timer timer = new Timer
(
async _ =>
{
var local = Interlocked.Read(ref counter);
Interlocked.Increment(ref counter);
await ReportMonitoring(1);
if (local % 2 == 0)
{
await ReportMonitoring(2);
}
if (counter % (3 * 12) == 0)
{
await ReportMonitoring(3);
await ReportMonitoring(4);
await ReportMonitoring(5);
}
},
null,
TimeSpan.Zero,
TimeSpan.FromMinutes(5)
);
另请注意that:
As long as you are using a Timer, you must keep a reference to it. As with any managed object, a Timer is subject to garbage collection when there are no references to it. The fact that a Timer is still active does not prevent it from being collected.
出于好奇,我也尝试了与 System.Timers 相同的逻辑。我在 class 中创建了定时器实例,这样它就不会在方法关闭时被释放。在该方法中,我已为计时器属性分配了所需的值。因为 System.Timers 能够每隔一段时间发生 运行 事件,所以我从上面使用@Guru 的逻辑到事件中以调用我的 ReportMonitoring 方法。我希望它能对将来的人派上用场。
using System;
using System.Threading;
using System.Timers;
using _logger = DemoProject.Common.Service;
namespace ReportMonitoringService
{
public class Worker
{
private System.Timers.Timer timer = new System.Timers.Timer();
private double _intervalTime = 300000; // 5mins
private bool _timerInUse = false;
private long _counter = 0L;
private async void StartMonitoringTimer()
{
try
{
timer.Elapsed += new ElapsedEventHandler(this.ReportDownload);
timer.Interval = _intervalTime; //5 mins in milliseconds
timer.Enabled = true;
}
catch (Exception ex)
{
await _logger.Error($"Monitoring failed exception: {ex}");
}
}
private async void ReportDownload(object source, ElapsedEventArgs e)
{
var local = Interlocked.Read(ref _counter);
Interlocked.Increment(ref _counter);
if (_timerInUse == false)
{
_timerInUse = true;
try
{
int _numReports;
if (local % 2 == 0) { _numReports = 2; }
else if (_counter % (3 * 12) == 0) { _numReports = 5; }
else { _numReports = 1; }
await ReportMonitoring(_numReports);
}
catch (Exception ex)
{
await _logger.Error($"Timer function threw exception downloading from Server");
await AppendLogtoFile("error: {ex.Message} stack trace: {ex.StackTrace}", LogType.Error);
}
_timerInUse = false;
}
}
}
}
我有用于从网络位置提取报告的服务。要求是每 5 分钟我需要调出报告 1,每 10 分钟报告 2,每 3 小时报告 3、4、5。因此,我在一个单独的 worker class 的方法内创建了一个计时器,我在其中使用了 System.Threading.Timer 的 5 个实例。报告正在被撤回,但顺序不正确。我怎样才能 运行 计时器使报告可以按特定顺序提取或使用 1 个计时器安排以特定方式提取报告?
这是我到目前为止所做的:
private async void pullReports()
{
try
{
await _logger.Info($"Start Report Monitoring");
Timer timer = new Timer
(
async e => await Service.ReportMonitoring(reportNum: 1),
null,
TimeSpan.Zero,
TimeSpan.FromMinutes(5)
);
Timer timer2 = new Timer
(
async e => await Service.ReportMonitoring(reportNum: 2),
null,
TimeSpan.Zero,
TimeSpan.FromMinutes(10)
);
Timer timer3 = new Timer
(
async e => await Service.ReportMonitoring(reportNum: 3),
null,
TimeSpan.Zero,
TimeSpan.FromHours(3)
);
Timer timer4 = new Timer
(
async e => await Service.ReportMonitoring(reportNum: 4),
null,
TimeSpan.Zero,
TimeSpan.FromHours(3)
);
Timer timer5 = new Timer
(
async e => await Service.ReportMonitoring(reportNum: 5),
null,
TimeSpan.Zero,
TimeSpan.FromHours(3)
);
}
catch (Exception ex)
{
await _logger.Error($"Start Report Monitoring exception: {ex}");
}
}
感谢任何类型的代码改进。我认为因为我的方法 Service.ReportMonitoring() 是异步的,所以这就是扰乱收集顺序的原因。但我不确定。
ReportNum的代码如下:
private static Task<Stream> ReportMonitoring(int repnum)
{
string _urlDataFormat = "https://{0}/cgi-bin/CGILink?cmd=vtranssetz&period=2&reptnum={1}";
string dataUrl = string.Format(_urlDataFormat, <serverIP>, repnum);
return HttpService.ExecuteGetStreamAsync(dataUrl);
}
如果报告的顺序很重要(因此数字较大的应该始终排在数字较小的之后),您应该这样做:
var counter = 0L;
Timer timer = new Timer
(
async _ =>
{
var local = Interlocked.Read(ref counter);
Interlocked.Increment(ref counter);
await ReportMonitoring(1);
if (local % 2 == 0)
{
await ReportMonitoring(2);
}
if (counter % (3 * 12) == 0)
{
await ReportMonitoring(3);
await ReportMonitoring(4);
await ReportMonitoring(5);
}
},
null,
TimeSpan.Zero,
TimeSpan.FromMinutes(5)
);
另请注意that:
As long as you are using a Timer, you must keep a reference to it. As with any managed object, a Timer is subject to garbage collection when there are no references to it. The fact that a Timer is still active does not prevent it from being collected.
出于好奇,我也尝试了与 System.Timers 相同的逻辑。我在 class 中创建了定时器实例,这样它就不会在方法关闭时被释放。在该方法中,我已为计时器属性分配了所需的值。因为 System.Timers 能够每隔一段时间发生 运行 事件,所以我从上面使用@Guru 的逻辑到事件中以调用我的 ReportMonitoring 方法。我希望它能对将来的人派上用场。
using System;
using System.Threading;
using System.Timers;
using _logger = DemoProject.Common.Service;
namespace ReportMonitoringService
{
public class Worker
{
private System.Timers.Timer timer = new System.Timers.Timer();
private double _intervalTime = 300000; // 5mins
private bool _timerInUse = false;
private long _counter = 0L;
private async void StartMonitoringTimer()
{
try
{
timer.Elapsed += new ElapsedEventHandler(this.ReportDownload);
timer.Interval = _intervalTime; //5 mins in milliseconds
timer.Enabled = true;
}
catch (Exception ex)
{
await _logger.Error($"Monitoring failed exception: {ex}");
}
}
private async void ReportDownload(object source, ElapsedEventArgs e)
{
var local = Interlocked.Read(ref _counter);
Interlocked.Increment(ref _counter);
if (_timerInUse == false)
{
_timerInUse = true;
try
{
int _numReports;
if (local % 2 == 0) { _numReports = 2; }
else if (_counter % (3 * 12) == 0) { _numReports = 5; }
else { _numReports = 1; }
await ReportMonitoring(_numReports);
}
catch (Exception ex)
{
await _logger.Error($"Timer function threw exception downloading from Server");
await AppendLogtoFile("error: {ex.Message} stack trace: {ex.StackTrace}", LogType.Error);
}
_timerInUse = false;
}
}
}
}