我注意到计时器不正确。
这是一个非常简单的C#代码:它将每1分钟打印一次当前日期/时间。 我的预期结果是:让它在下午3:30运行,那么我们将有:3:31 PM,3:32 PM,3:33 PM,...
但是有时没有收到上述结果:有时是3:31 PM,3:32 PM,3:34 PM等...
因此它丢失了1行。
谁能指出我是什么问题?
class Program
{
static Timer m_Timer;
static int countDown;
static void Main(string[] args)
{
countDown = 60;
m_Timer = new Timer(TimerCallback, null, 0, 1000);
while (true) { System.Threading.Thread.Sleep(10); };
}
static void TimerCallback(Object o)
{
countDown -= 1;
if (countDown <= 0)
{
Console.WriteLine(" ===>>>>>" + System.DateTime.Now.ToString());
countDown = 60;
}
System.Threading.Thread.Sleep(10000); //long running code demo
}
}
答案 0 :(得分:2)
Windows-不是实时操作系统。因此,如果您希望计时器准确地等待1秒,那就错了。计时器可以等待更多时间的原因很多。由于timer resolution或其他高负载操作。
答案 1 :(得分:2)
System.Threading.Timer在线程池中的线程上运行。您运行回调函数,该函数每1秒在池中的一个线程上运行一次,并使用睡眠将其阻塞10秒。根据在某些时间点线程池中有多少线程,它们都可能被阻塞并等待,否则.NET应该为您分配新线程,直到您池中的线程数上限为止。
答案 2 :(得分:0)
上面的代码导致您每秒运行10秒钟的“演示”(睡眠)。您将同时运行10个工作线程。
您确定这是您要实现的目标吗?
要查看您的应用实际发生了什么,只需添加:
Console.WriteLine($"Time:{DateTime.Now.ToString("hh:mm:ss.fff tt")},Thread:{Thread.CurrentThread.ManagedThreadId},countDown:{countDown}");
在TimerCallback开头的。您会注意到,后面的回调之间的时间间隔不完全是1000毫秒(通常是一点点)。这在非rtc操作系统中是完全正常的,并且在大多数情况下-这不是问题。请记住,该计时器并不准确。
此外,如果您尝试以这种方式使用Timer并尝试计算滴答声-这些小错误会在随后的滴答声中累积。
答案 3 :(得分:0)
如果您喜欢较新的.NET TPL语法,则可以这样编写:
using System;
using System.Threading.Tasks;
namespace ConsoleApp1
{
internal class Program
{
private static void Main(string[] args)
{
Repeat(TimeSpan.FromSeconds(10));
Console.ReadKey();
}
private static void Repeat(TimeSpan period)
{
Task.Delay(period)
.ContinueWith(
t =>
{
//Do your staff here
Console.WriteLine($"Time:{DateTime.Now}");
Repeat(period);
});
}
}
}
答案 4 :(得分:0)
我使用另一种方式,并且效果更好:计算时间之间的时差
class Program
{
static Timer m_Timer;
static DateTime lastRun;
static int CHECK_POINT = 60;
static void Main(string[] args)
{
lastRun = DateTime.Now;
m_Timer = new Timer(TimerCallback, null, 0, 1000);
while (true) { System.Threading.Thread.Sleep(10); };
}
static void TimerCallback(Object o)
{
if((DateTime.Now- lastRun).TotalSeconds >= CHECK_POINT)
{
lastRun = DateTime.Now;
Console.WriteLine(" ===>>>>>" + System.DateTime.Now.ToString());
}
System.Threading.Thread.Sleep(10000); //long running code demo
}
}
答案 5 :(得分:0)
我只是将这里发现的内容发布给像我这样有问题的人。 我从另一个线程找到了答案。 我使用“ HighResolutionTimer.cs”,它可以完美运行: https://gist.github.com/DraTeots/436019368d32007284f8a12f1ba0f545