系统。线程。定时器在 C # 它似乎不工作。它运行非常快,每3秒

我有一个计时器对象。我希望每分钟都能播放。具体来说,它应该运行一个 OnCallBack方法,并在运行 OnCallBack方法时变为非活动状态。一旦 OnCallBack方法完成,它(OnCallBack)重新启动计时器。

以下是我目前掌握的情况:

private static Timer timer;


private static void Main()
{
timer = new Timer(_ => OnCallBack(), null, 0, 1000 * 10); //every 10 seconds
Console.ReadLine();
}


private static void OnCallBack()
{
timer.Change(Timeout.Infinite, Timeout.Infinite); //stops the timer
Thread.Sleep(3000); //doing some long operation
timer.Change(0, 1000 * 10);  //restarts the timer
}

然而,它似乎不工作。它每3秒跑得非常快。即使提高一个周期(1000 * 10)。它似乎对 1000 * 10视而不见

我做错了什么?

183104 次浏览

没有必要停止计时器,从这篇文章中看到不错的解决方案:

”您可以让计时器继续触发回调方法,但将不可重入的代码封装在 Monitor 中。尝试进入/退出。在这种情况下,不需要停止/重新启动计时器; 重叠的调用不会获得锁并立即返回。”

private void CreatorLoop(object state)
{
if (Monitor.TryEnter(lockObject))
{
try
{
// Work here
}
finally
{
Monitor.Exit(lockObject);
}
}
}

我会这么做:

private static Timer timer;
private static void Main()
{
timer = new Timer(_ => OnCallBack(), null, 1000 * 10,Timeout.Infinite); //in 10 seconds
Console.ReadLine();
}


private static void OnCallBack()
{
timer.Dispose();
Thread.Sleep(3000); //doing some long operation
timer = new Timer(_ => OnCallBack(), null, 1000 * 10,Timeout.Infinite); //in 10 seconds
}

忽略周期参数,因为您试图自己控制周期。


您的原始代码正在尽可能快地运行,因为您一直为 dueTime参数指定 0:

如果 dueTime 为零(0) ,则立即调用回调方法。

使用 System.Threading.Timer是强制性的吗?

如果没有,System.Timers.Timer有方便的 Start()Stop()方法(还有一个可以设置为 false 的 AutoReset属性,这样就不需要 Stop(),执行后只需调用 Start())。

这不是系统的正确用法。穿线。计时器。在实例化 Timer 时,几乎总是应该执行以下操作:

_timer = new Timer( Callback, null, TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite );

这将指示计时器在时间间隔过去时只计时一次。然后在回调函数中,在工作完成后更改计时器,而不是在工作完成前更改计时器。例如:

private void Callback( Object state )
{
// Long running operation
_timer.Change( TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite );
}

因此不需要锁定机制,因为没有并发性。计时器将在下一个间隔过去 + 长时间运行操作的时间后触发下一个回调。

如果你需要在精确的 N 毫秒运行你的计时器,那么我建议你使用秒表来测量长时间运行操作的时间,然后适当地调用 Change 方法:

private void Callback( Object state )
{
Stopwatch watch = new Stopwatch();


watch.Start();
// Long running operation


_timer.Change( Math.Max( 0, TIME_INTERVAL_IN_MILLISECONDS - watch.ElapsedMilliseconds ), Timeout.Infinite );
}

我鼓励任何人做。NET,并使用 CLR 谁没有读过杰弗里里希特的书-CLR via C#,读是尽快的。计时器和线程池在那里有详细的解释。

 var span = TimeSpan.FromMinutes(2);
var t = Task.Factory.StartNew(async delegate / () =>
{
this.SomeAsync();
await Task.Delay(span, source.Token);
}, source.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);


source.Cancel(true/or not);


// or use ThreadPool(whit defaul options thread) like this
Task.Start(()=>{...}), source.Token)

如果你喜欢使用一些循环线程内..。

public async void RunForestRun(CancellationToken token)
{
var t = await Task.Factory.StartNew(async delegate
{
while (true)
{
await Task.Delay(TimeSpan.FromSeconds(1), token)
.ContinueWith(task => { Console.WriteLine("End delay"); });
this.PrintConsole(1);
}
}, token) // drop thread options to default values;
}


// And somewhere there
source.Cancel();
//or
token.ThrowIfCancellationRequested(); // try/ catch block requred.