.NET,事件每分钟(分钟)。 计时器是最好的select吗?
我想用c#在Windows窗体应用程序中每分钟(按时钟)做东西。 我只是想知道什么是最好的方式去呢?
我可以使用一个定时器,并将其间隔设置为60000,但为了让它在一分钟内运行,我将不得不在一分钟内启用它,而不是真正可行的。
我可以使用一个计时器,并将其间隔设置为1000.然后在其tick事件中,我可以检查时钟当前分钟对我设置的variables,如果分钟已经改变,然后运行我的代码。 这让我很担心,因为我正在每隔1秒钟让计算机做一次检查,以便每1分钟执行一次工作。 当然这很难看?
我正在使用Windows窗体和.Net 2.0,所以不想使用.Net 3.5自带的DispatchTimer
这一定是一个相当普遍的问题。 有没有更好的方法来做到这一点?
build立在可以漂移的水瓶座的答案上,并且在一分钟之内不会在分钟内精确地打上:
static System.Timers.Timer t; static void Main(string[] args) { t = new System.Timers.Timer(); t.AutoReset = false; t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed); t.Interval = GetInterval(); t.Start(); Console.ReadLine(); } static double GetInterval() { DateTime now = DateTime.Now; return ((60 - now.Second) * 1000 - now.Millisecond); } static void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { Console.WriteLine(DateTime.Now.ToString("o")); t.Interval = GetInterval(); t.Start(); }
在我的盒子里,这个代码在每分钟的.02s内一致地打勾:
2010-01-15T16:42:00.0040001-05:00 2010-01-15T16:43:00.0014318-05:00 2010-01-15T16:44:00.0128643-05:00 2010-01-15T16:45:00.0132961-05:00
怎么样:
int startin = 60 - DateTime.Now.Second; var t = new System.Threading.Timer(o => Console.WriteLine("Hello"), null, startin * 1000, 60000);
创build一个每隔1秒触发一次的Timer
控件(通常只做一个简单的检查)将会给应用程序增加可忽略的开销。
只需将Environment.TickCount
或DateTime.Now
的值与上次存储的时间(前一个“分钟”)进行比较,即可获得相当精确的解决scheme。 这两个时间值的分辨率是大约15ms,这应该足够您的目的。
但请注意, Timer
控件的时间间隔不能保证是精确的,或者甚至是现在的任何地方,因为它在Windows消息循环上运行,这与UI的响应性相关。 永远不要依赖它,即使是适度的时间精确度 – 虽然它足够发射重复事件,你可以使用更灵敏的方法来检查时间,比如上面给出的两个之一。
你可以用反应式扩展来指定这个,它会为你处理很多与定时器相关的问题(时钟变化,应用程序hibernate等)。 使用Nuget包Rx-Main,代码如下:
Action work = () => Console.WriteLine(DateTime.Now.ToLongTimeString()); Scheduler.Default.Schedule( // start in so many seconds TimeSpan.FromSeconds(60 - DateTime.Now.Second), // then run every minute () => Scheduler.Default.SchedulePeriodic(TimeSpan.FromMinutes(1), work)); Console.WriteLine("Press return."); Console.ReadLine();
在这里阅读(search“介绍ISchedulerPeriodic”)以查看所有这些照顾的问题: http : //blogs.msdn.com/b/rxteam/archive/2012/06/20/reactive-extensions-v2-0 -release候补可供now.aspx
我jsut使用WPF DispatcherTimer编写了这个类,但是您可以将调度程序交换为支持在从睡眠状态唤醒时进行更改的任何计时器。
课程是build立在一个固定的时间步骤,并支持启动/停止/重置,启动/停止/启动像恢复操作一样工作。 计时器就像这样的秒表。
一个时钟实现只需创build一个间隔为1秒的类,并听取事件。 要小心,这是一个实时时钟,如果tick事件花费的时间比完成时间要长,你会注意到时钟会试着赶上实时,这将引发一连串的tick事件。
public class FixedStepDispatcherTimer { /// <summary> /// Occurs when the timer interval has elapsed. /// </summary> public event EventHandler Tick; DispatcherTimer timer; public bool IsRunning { get { return timer.IsEnabled; } } long step, nextTick, n; public TimeSpan Elapsed { get { return new TimeSpan(n * step); } } public FixedStepDispatcherTimer(TimeSpan interval) { if (interval < TimeSpan.Zero) { throw new ArgumentOutOfRangeException("interval"); } this.timer = new DispatcherTimer(); this.timer.Tick += new EventHandler(OnTimerTick); this.step = interval.Ticks; } TimeSpan GetTimerInterval() { var interval = nextTick - DateTime.Now.Ticks; if (interval > 0) { return new TimeSpan(interval); } return TimeSpan.Zero; // yield } void OnTimerTick(object sender, EventArgs e) { if (DateTime.Now.Ticks >= nextTick) { n++; if (Tick != null) { Tick(this, EventArgs.Empty); } nextTick += step; } var interval = GetTimerInterval(); Trace.WriteLine(interval); timer.Interval = interval; } public void Reset() { n = 0; nextTick = 0; } public void Start() { var now = DateTime.Now.Ticks; nextTick = now + (step - (nextTick % step)); timer.Interval = GetTimerInterval(); timer.Start(); } public void Stop() { timer.Stop(); nextTick = DateTime.Now.Ticks % step; } }
运行一些代码来查看分钟是否每秒变化一次不需要太多的CPU时间,应该是可以接受的。
那么Quartz.NET呢? 我认为它是一个很好的框架来做定时的行动。
创build一个方法或把这个代码放在你想要定时器启动的地方:
int time = 60 - DateTime.Now.Second; // Gets seconds to next minute refreshTimer.Interval = time * 1000; refreshTimer.Start();
然后在你的tick事件中设置间隔为60000:
private void refreshTimer_Tick(object sender, EventArgs e) { refreshTimer.Interval = 60000; // Sets interval to 60 seconds // Insert Refresh logic }
通过使用ReactiveExtensions,你可以使用下面的代码,如果你有兴趣做一些简单的事情,比如打印到控制台。
using System; using System.Reactive.Linq; namespace ConsoleApplicationExample { class Program { static void Main() { Observable.Interval(TimeSpan.FromMinutes(1)) .Subscribe(_ => { Console.WriteLine(DateTime.Now.ToString()); }); Console.WriteLine(DateTime.Now.ToString()); Console.ReadLine(); } } }
你可以设置两个定时器。 一个初始的短时间间隔计时器(可能每秒钟都会启动,但是取决于第二个计时器必须在一分钟内如何发火)。
您只会启动短间隔计时器,直到达到主间隔计时器的所需开始时间。 一旦达到初始时间,第二个主间隔定时器可以被激活,并且短间隔定时器可以被去激活。
void StartTimer() { shortIntervalTimer.Interval = 1000; mainIntervalTimer.Interval = 60000; shortIntervalTimer.Tick += new System.EventHandler(this.shortIntervalTimer_Tick); mainIntervalTimer.Tick += new System.EventHandler(mainIntervalTimer_Tick); shortIntervalTimer.Start(); } private void shortIntervalTimer_Tick(object sender, System.EventArgs e) { if (DateTime.Now.Second == 0) { mainIntervalTimer.Start(); shortIntervalTimer.Stop(); } } private void mainIntervalTimer_Tick(object sender, System.EventArgs e) { // do what you need here // }
或者,你可以睡觉暂停执行,直到它超时,这应该是接近你想要的时间。 这只会在睡眠结束时唤醒计算机,这样可以节省CPU时间,并让CPU在处理事件之间断电。
这具有修改超时的优点,使其不会漂移。
int timeout = 0; while (true) { timeout = (60 - DateTime.Now.Seconds) * 1000 - DateTime.Now.Millisecond; Thread.Sleep(timeout); // do your stuff here }
使用定时器设置为每秒运行一次(或毫秒,无论您的准确度阈值是多less),然后编写方法以运行您的function,当且仅当当前时间在“分钟”点之后的阈值内。
我用于计划任务的是一个System.Threading.Timer(System.Threading.TimerCallback,object,int,int),其中的callback设置为我要执行的代码,基于以毫秒为单位提供的时间间隔期价值。
怎么样aquinas的答案和“民意测验”的组合:(道歉混合语言)
def waitForNearlyAMinute: secsNow = DateTime.Now.Second; waitFor = 55 - secsNow; setupTimer(waitFor, pollForMinuteEdge) def pollForMinuteEdge: if (DateTime.Now.Second == 0): print "Hello, World!"; waitForNearlyAMinute(); else: setupTimer(0.5, pollForMinuteEdge)