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