简体   繁体   中英

Running multiple timers simultaneously in C# using System.Threading

I have service that I am using to pull up reports from a network location. The requirement is that ever 5 minutes I need to pull up report 1, every 10 minutes report 2 & every 3 hours report 3,4,5. So, I created a timer inside a method on a separate worker class where I am using 5 instances of System.Threading.Timer. The reports are getting pulled but not in proper order. How can I run the timers in such a way that reports can get pulled in a specific order or use 1 timer to schedule pulling of reports in specific manner?

Here's what I have done so far:

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}");
        }
       
    }

Any kind of code improvements are appreciated. I think because my method Service.ReportMonitoring() is asynchronous that is the reason that is disturbing the order of collection. But I'm not sure about that.

The code for ReportNum is as follows:

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);
        }

If order of the reports is important (so the ones with higher numbers should always be after those with lower numbers) you should do something like that:

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)
);

Also note 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.

Out of curiosity I have also tried the same kind of logic with System.Timers. I created the timer instance in the class so that it won't get disposed when the method closes. In the method I have assigned required values to the timer properties. Because System.Timers have an ability to run events at intervals I have used @Guru's logic from above into the event to invoke my ReportMonitoring Method. I hope it comes handy to someone in future.

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;
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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