C#定期发射功能的正确方法

时间:2016-05-24 06:23:06

标签: c# timer timing

我有大约20个函数,其中一些应该每秒触发一次,一些,每秒20次,另外一次每分钟两次,我现在有类似的东西:

                DateTime nowVar = DateTime.Now;
                var lastExecutionFunc1 = nowVar;
                var lastExecutionFunc2 = nowVar;
                var lastExecutionFunc3 = nowVar;
                var lastExecutionFunc4 = nowVar;

        DateTime _now = DateTime.Now;


                if ((_now - lastExecutionFunc1).TotalSeconds >= 0.1)
                        {
                            lastExecutionFunc1 = _now;
                            //dosomething
                        }
               if ((_now - lastExecutionFunc2).TotalSeconds >= 0.5)
                        {
                            lastExecutionFunc2 = _now;
                            //do something else
                        }
               if ((_now - lastExecutionFunc3).TotalSeconds >= 30)
                        {
                            lastExecutionFunc3 = _now;
                            //do something else
                        }
.....

虽然这有效,但我不禁认为应该有更优雅的方式来做到这一点。创建一个var来存储每个执行使得核心看起来非常混乱。猜猜我可以使用对,但这也不会太好。

有什么建议吗?

编辑:如果你想看看我想要完成的事情,you can see the whole code here。在第525行。

3 个答案:

答案 0 :(得分:3)

你为这个定时活动写了一个无限循环吗?非常糟糕的做法。 如果你们中的任何一个“做某事”持续很长时间,所有其他功能(和主程序)将停止工作。如果你的功能可以独立工作,让他们独立工作,并为每个功能使用不同的计时器。如果某些函数是独占函数,请使用信号量(静态成员)以避免并行工作。

答案 1 :(得分:3)

下面的代码展示了一个带有同步锁的基本调度程序。

using System;
using System.Collections.Generic;
using System.Timers;

namespace TimerUsage
{
    class Program
    {
        static void Main(string[] args)
        {
            Scheduler scheduler = new Scheduler();
            scheduler.ScheduleMethod(100, () => Console.WriteLine("func1"));
            scheduler.ScheduleMethod(200, () => Console.WriteLine("func2"));
            scheduler.ScheduleMethod(300, () => Console.WriteLine("func3"));
            scheduler.ScheduleMethod(1000, () => Console.WriteLine("func4"));
            scheduler.Run();
            System.Threading.Thread.Sleep(10000);
        }

    }

    public class Scheduler
    {
        private Dictionary<int, Row> _schedule = new Dictionary<int, Row>();

        public void ScheduleMethod(int interval, Action method)
        {
            Row row;
            if (!_schedule.TryGetValue(interval, out row))
            {
                row = new Row(interval);
                _schedule[interval] = row;
            }
            row.AddMethod(method);
        }

        public void Run()
        {
            foreach (var item in _schedule)
            {
                item.Value.StartTimer();
            }
        }
    }

    internal class Row
    {
        private object _syncLock = new object();
        private Timer _timer;
        private List<Action> _methods = new List<Action>();

        public Row(int interval)
        {
            _timer = new System.Timers.Timer(interval);
            _timer.Elapsed += ExecuteItems;
        }

        private void ExecuteItems(object sender, ElapsedEventArgs e)
        {
            lock (_syncLock)
            {
                foreach (var method in _methods)
                {
                    method();
                }
            }
        }

        public void AddMethod(Action method)
        {
            _methods.Add(method);
        }

        public void StartTimer()
        {
            _timer.Start();
        }

    }

}

答案 2 :(得分:1)

这是一种方法:

我创建了一个使用Action委托将方法与其间隔绑定的类:

public class ActionInvoker
{
    private DateTime _LastRunTime;
    private Action _Action;
    private double _Interval;

    public ActionInvoker(Action action, double interval)
    {
        _Action = action;
        _Interval = interval;
        _LastRunTime = DateTime.Now;
    }


    public void InvokeAction()
    {
        var now = DateTime.Now;
        if ((now - _LastRunTime).TotalMilliseconds >= _Interval)
        {
            _LastRunTime = now;
            _Action.Invoke();
        }
    }

我添加了一个ActionInvoker列表作为表单的私有成员:

private List<ActionInvoker> _Actions;

现在,在表单的构造函数中,我已经完成了这个:

_Actions = new List<ActionInvoker>();

_Actions.Add(new ActionInvoker(DoThis, 10000));
_Actions.Add(new ActionInvoker(DoThat, 3000));

现在我在Timer.Tick事件处理程序中的所有内容都是这段代码:

foreach(var ai in _Actions)
{
    ai.InvokeAction();
}

当然,这只是一个基本的POC,如果要将参数发送到方法,或者方法返回值,则需要进一步开发它。

另请注意,您最好将这些方法作为async运行,以防止用户界面冻结,直到完成为止。