C#周期触发功能的正确方式

C#周期触发功能的正确方式,c#,timer,timing,C#,Timer,Timing,我有大约20个函数,其中一些函数应该每秒触发一次,一些函数每秒触发20次,另一些函数每分钟触发两次,目前我有这样的函数: DateTime nowVar = DateTime.Now; var lastExecutionFunc1 = nowVar; var lastExecutionFunc2 = nowVar; var lastExecutionFunc3 = no

我有大约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来存储每次执行会使核心看起来非常混乱。我想我可以用这双,但那也不太好

有什么建议吗


编辑:如果你想看看我想完成什么。在第525行。

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

以下是一种方法:

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

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;
当然,这只是一个基本的POC,如果要向方法发送参数,或者如果方法返回值,则需要进一步开发它


另外请注意,最好以异步方式运行这些方法,以防止UI冻结,直到它们完成。

下面的代码提供了一个带有同步锁的基本计划程序

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

    }

}
使用系统;
使用System.Collections.Generic;
使用系统计时器;
命名空间时间图像
{
班级计划
{
静态void Main(字符串[]参数)
{
调度器调度器=新调度器();
ScheduleMethod(100,()=>Console.WriteLine(“func1”);
ScheduleMethod(200,()=>Console.WriteLine(“func2”);
ScheduleMethod(300,()=>Console.WriteLine(“func3”);
ScheduleMethod(1000,()=>Console.WriteLine(“func4”);
scheduler.Run();
系统线程线程睡眠(10000);
}
}
公共类调度程序
{
专用词典_schedule=新词典();
public void ScheduleMethod(int interval,Action method)
{
行行;
if(!\u schedule.TryGetValue(间隔,行外))
{
行=新行(间隔);
_计划[间隔]=行;
}
行。添加方法(方法);
}
公开募捐
{
foreach(风险值项目在_计划中)
{
item.Value.StartTimer();
}
}
}
内部类行
{
私有对象_syncLock=新对象();
私人定时器;
私有列表_方法=新列表();
公共行(整数间隔)
{
_定时器=新系统定时器定时器定时器(间隔);
_timer.appeased+=ExecuteItems;
}
私有void ExecuteItems(对象发送方,ElapsedEventArgs e)
{
锁(同步锁)
{
foreach(var方法在_方法中)
{
方法();
}
}
}
公共无效添加方法(操作方法)
{
_方法:添加(方法);
}
公共无效StartTimer()
{
_timer.Start();
}
}
}

您可以使用Timer类,创建一个函数数组,然后根据递增的计数器将其直接输入计时器回调,怎么样?最简单的解决方案是使用计时器比我目前使用的计时器更不雅观。我不认为这是问题所在。当一个计时器可以处理所有20种方法时,在一个窗体上使用20个计时器似乎是浪费资源。当然,如果可能的话,它们应该是
async
方法。是的,它们在while(true)块中,但是它们在与主程序不同的线程上工作。任何函数都不可能占用超过几个时钟周期。他们只是从某个地方取一个字符串,然后复制到另一个字符串。这似乎是一个很好的方法。但我不确定我是否理解“行动”业务是如何运作的。我应该把什么传递给它?顺便说一句,我运行的函数不接受任何参数,也不返回任何内容。他们只是修改了一些全局变量。如果您想查看代码,我已经在原始帖子中添加了一个指向我的项目的链接。我已经编辑了我的答案,将指向
操作
委托的MSDN页面的链接包括在内。是的,我已经阅读了一些关于操作类型的内容。看起来很有用,不知道我怎么到现在才注意到。谢谢。@侧翼者
行动的另一种选择是
委托
——从某种意义上说,这是一种更强烈的类型。Benim kullanım alanım için biraz fazla teferruatlıduruyor ama teşekkürler.Rica ederim。“kopyalayarak kolay birşekilde Kullabilirsiniz”类,特弗鲁特·库兰·佐尔卢·奥卢·图尔马亚卡特(teferruat kısmıkullanım zorluğu oluşturmayacakt r)。
foreach(var ai in _Actions)
{
    ai.InvokeAction();
}
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();
        }

    }

}