C# .NET,每分钟一次(按分钟)。定时器是最好的选择吗?
我想用c#在windows窗体应用程序中每分每秒(按时钟)做一些事情。我只是想知道最好的办法是什么 我可以使用计时器并将其间隔设置为60000,但要让它在一分钟内运行,我必须精确地在一分钟内启用它,这不是真正可行的 我可以使用计时器,将其间隔设置为1000。然后在它的tick事件中,我可以对照我设置的变量检查当前分钟的时钟,如果分钟发生了变化,那么运行我的代码。这让我担心,因为我让我的电脑每1秒检查一次,以便每1分钟执行一次工作。这肯定很难看吧 我使用的是windows窗体和.Net 2.0,因此不想使用.Net 3.5附带的C# .NET,每分钟一次(按分钟)。定时器是最好的选择吗?,c#,winforms,timer,C#,Winforms,Timer,我想用c#在windows窗体应用程序中每分每秒(按时钟)做一些事情。我只是想知道最好的办法是什么 我可以使用计时器并将其间隔设置为60000,但要让它在一分钟内运行,我必须精确地在一分钟内启用它,这不是真正可行的 我可以使用计时器,将其间隔设置为1000。然后在它的tick事件中,我可以对照我设置的变量检查当前分钟的时钟,如果分钟发生了变化,那么运行我的代码。这让我担心,因为我让我的电脑每1秒检查一次,以便每1分钟执行一次工作。这肯定很难看吧 我使用的是windows窗体和.Net 2.0,因
DispatchTimer
这一定是一个相当普遍的问题。你们有没有更好的方法来做到这一点?运行一些代码,看看每秒钟分钟是否改变一次,这不需要太多的CPU时间,应该是可以接受的。创建一个每1秒触发一次的控件(通常只做简单的检查)会给应用程序增加微不足道的开销 只需将或的值与上次存储的时间(前一个“分钟刻度”)进行比较,就可以得到一个相当精确的解决方案。这两个时间值的分辨率约为15毫秒,这对于您的目的来说应该足够了
但是,请注意,
计时器的时间间隔
控件的时间间隔不能保证精确到现在的任何位置,因为它在Windows消息循环上运行,这与UI的响应性有关。即使是中等精度的计时,也不要依赖它——尽管它足以触发重复事件,您可以使用更敏感的方法(如上面给出的两种方法之一)检查时间。使用定时器设置为每秒运行一次(或毫秒,无论精度阈值是多少),然后编写方法,当且仅当当前时间在该阈值内且超过了“分钟”点时运行功能。我用于计划任务的是System.Threading.Timer(System.Threading.TimerCallback,object,int,int)将回调设置为我希望根据周期值的间隔(以毫秒为单位)执行的代码。如何:
int startin = 60 - DateTime.Now.Second;
var t = new System.Threading.Timer(o => Console.WriteLine("Hello"),
null, startin * 1000, 60000);
阿奎那的回答和民意调查的结合怎么样?(为混合语言道歉)
你可以设置两个计时器。一个初始的短间隔计时器(可能每秒钟触发一次,但取决于第二个计时器在一分钟内必须触发的频率) 您只能在达到主间隔计时器的所需开始时间之前启动短间隔计时器。一旦达到初始时间,可激活第二个主间隔计时器,并停用短间隔计时器
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
}
以阿奎那的答案为基础,阿奎那的答案可能会漂移,而且不会在一分钟内准确地滴答作响:
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();
}
在我的方框中,此代码在每分钟0.02秒内持续滴答:
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
我jsut使用WPF Dispatchermer编写了这个类,但是您可以将dispatcher替换为任何支持在从睡眠状态唤醒时进行更改的计时器 该类使用固定的时间步长构造,支持启动/停止/重置,启动/停止/启动的工作方式类似于恢复操作。在这方面,计时器就像秒表 时钟实现只需创建间隔为1秒的类并侦听事件。尽管这是一个实时时钟,但要小心,如果滴答声事件的完成时间长于间隔,您会注意到时钟将试图赶上实时,这将导致引发一系列滴答声事件
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;
}
}
公共类FixedStepDispatcher
{
///
///在计时器间隔已过时发生。
///
公共事件处理程序;
调度定时器;
public bool正在运行{get{return timer.IsEnabled;}}
长步,下一步,n;
公共时间跨度已过{获取{返回新时间跨度(n*步);}
公共固定步骤分派器(时间跨度间隔)
{
if(间隔<时间间隔0)
{
抛出新ArgumentOutOfRangeException(“interval”);
}
this.timer=new dispatchermer();
this.timer.Tick+=新的EventHandler(OnTimerTick);
this.step=interval.Ticks;
}
TimeSpan GetTimerInterval()
{
var interval=nextTick-DateTime.Now.Ticks;
如果(间隔>0)
{
返回新的时间跨度(间隔);
}
返回TimeSpan.Zero;//收益率
}
void OnTimerTick(对象发送方,事件参数e)
{
如果(DateTime.Now.Ticks>=nextTick)
{
n++;
如果(勾选!=null)
{
勾选(此,EventArgs.Empty);
}
nextTick+=步长;
}
var interval=GetTimerInterval();
Trace.WriteLine(间隔);
计时器。间隔=间隔;
}
公共无效重置()
{
n=0;
nextTick=0;
}
公开作废开始()
{
var now=DateTime.now.Ticks;
nextTick=now+(步骤-(nextTick%步骤));
timer.Interval=GetTimerInterval();
timer.Start();
}
公共停车场()
{
timer.Stop();
nextTick=DateTime.Now.Ticks%step;
}
}
您可以使用反应式扩展解决这一问题,它将处理大量与计时器相关的问题
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;
}
}
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();
int time = 60 - DateTime.Now.Second; // Gets seconds to next minute
refreshTimer.Interval = time * 1000;
refreshTimer.Start();
private void refreshTimer_Tick(object sender, EventArgs e)
{
refreshTimer.Interval = 60000; // Sets interval to 60 seconds
// Insert Refresh logic
}
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();
}
}
}
static void Main(string[] args)
{
//constatnt total miliseconds to one minute
const Int32 minuteMilisecond = 60 * 1000;
//get actual datetime
DateTime actualDateTime = DateTime.UtcNow;
//compenzation to one minute
Int32 nexTimer = Environment.TickCount + ((59 - actualDateTime.Second) * 1000) + (999 - actualDateTime.Millisecond);
//random fuction to simulate different delays on thread
Random rnd = new Random();
//main loop
while (true)
{
if (Environment.TickCount > nexTimer)
{
nexTimer += minuteMilisecond;
//execute your code here every minute
Console.WriteLine($"actual DateTime: {DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss:ffff")}");
}
//random sleep between 100 - 200 ms
Thread.Sleep(rnd.Next(100, 200));
}
}