繁体   English   中英

使用 System.Threading 在 C# 中同时运行多个计时器

[英]Running multiple timers simultaneously in C# using System.Threading

我有用于从网络位置提取报告的服务。 要求是每 5 分钟我需要调出报告 1,每 10 分钟报告 2 和每 3 小时报告 3、4、5。 因此,我在一个单独的工作人员 class 的方法内创建了一个计时器,其中我使用了 5 个 System.Threading.Timer 实例。 报告正在被删除,但顺序不正确。 如何运行计时器以使报告可以按特定顺序提取或使用 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)
);

另请注意

只要您使用 Timer,就必须保留对它的引用。 与任何托管 object 一样,当没有对 Timer 的引用时,它会受到垃圾回收的影响。 Timer 仍然处于活动状态的事实并不能阻止它被收集。

出于好奇,我也用 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;
            }
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM