C# 为什么我的计时器开得早?

C# 为什么我的计时器开得早?,c#,timer,C#,Timer,我正试图在每一分钟精确地触发一个方法 我正在使用下面的代码,但是我注意到计时器可以提前几毫秒启动 我该怎么解决呢 public partial class Form1 : Form { DateTime RoundUpFuzzy(DateTime dt, TimeSpan d) { int n=1; if (dt.Millisecond > 900) n = 2

我正试图在每一分钟精确地触发一个方法

我正在使用下面的代码,但是我注意到计时器可以提前几毫秒启动

我该怎么解决呢

    public partial class Form1 : Form
    {

        DateTime RoundUpFuzzy(DateTime dt, TimeSpan d)
        {
            int n=1;
            if (dt.Millisecond > 900)
                n = 2;
            return new DateTime(((dt.Ticks + (d.Ticks*n) - 1) / d.Ticks) * d.Ticks);
        }

        public void HistMatch()
        {
            for (int i = 0; i < 10; i++)
            {
                var now = DateTime.UtcNow;
                var nextDT = RoundUpFuzzy(now, TimeSpan.FromMinutes(1));
                var waitTS = nextDT.Subtract(now);
                Console.WriteLine("Now: " + now.ToString("HH:mm:ss.fff") + " nextDT: " + nextDT.ToString("HH:mm:ss.fff")+" wait MS: " + waitTS.TotalMilliseconds);
                System.Threading.Thread.Sleep(waitTS);
            }
        }
}
编辑1-附加测试代码

在这里,我尝试3个版本来精确地每分钟运行一次事件。只有第一个“测试睡眠”是准确的。如何使用计时器获得相同的结果

public partial class Form1 : Form
{
    System.Threading.Timer threadingTimer;
    System.Timers.Timer timersTimer;

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Test_Sleep();
        Test_ThreadingTimer("");
        Test_TimersTimer("", null);
    }

    public void Test_TimersTimer(object o, System.Timers.ElapsedEventArgs e)
    {
        var now = DateTime.UtcNow;
        var nextDT = RoundUpFuzzy(now, TimeSpan.FromMinutes(1));
        var ms = nextDT.Subtract(now);
        Console.WriteLine("Now: " + now.ToString("HH:mm:ss.fff") + " nextDT: " + nextDT.ToString("HH:mm:ss.fff") + " waitMS: " + ms.TotalMilliseconds);
        timersTimer = new System.Timers.Timer();
        timersTimer.Interval = (int)ms.TotalMilliseconds;
        timersTimer.Elapsed += Test_TimersTimer;
        timersTimer.AutoReset = false;
        timersTimer.Enabled = true;
    }

    public void Test_ThreadingTimer(object o)
    {
        var now = DateTime.UtcNow;
        var nextDT = RoundUpFuzzy(now, TimeSpan.FromMinutes(1));
        var ms = nextDT.Subtract(now);
        Console.WriteLine("Now: " + now.ToString("HH:mm:ss.fff") + " nextDT: " + nextDT.ToString("HH:mm:ss.fff") + " waitMS: " + ms.TotalMilliseconds);
        threadingTimer = new System.Threading.Timer(new System.Threading.TimerCallback(Test_ThreadingTimer), null, ms, TimeSpan.FromMilliseconds(-1));
    }

    public void Test_Sleep()
    {
        for (int i = 0; i < 10; i++)
        {
            var now = DateTime.UtcNow;
            var nextDT = RoundUpFuzzy(now, TimeSpan.FromMinutes(1));
            var waitTS = nextDT.Subtract(now);
            Console.WriteLine("Now: " + now.ToString("HH:mm:ss.fff") + " nextDT: " + nextDT.ToString("HH:mm:ss.fff") + " waitMS: " + waitTS.TotalMilliseconds);
            System.Threading.Thread.Sleep(waitTS);
        }
    }

    DateTime RoundUpFuzzy(DateTime dt, TimeSpan d)
    {
        int n = 1;
        if (dt.Millisecond > 900)
            n = 2;
        return new DateTime(((dt.Ticks + (d.Ticks * n) - 1) / d.Ticks) * d.Ticks);
    }
}
公共部分类表单1:表单
{
System.Threading.Timer threadingTimer;
系统定时器定时器定时器定时器;
公共表格1()
{
初始化组件();
}
私有无效按钮1\u单击(对象发送者,事件参数e)
{
测试睡眠();
测试螺纹计时器(“”);
Test_TimersTimer(“”,null);
}
公共无效测试\u TimersTimer(对象o,System.Timers.ElapsedEventArgs e)
{
var now=DateTime.UtcNow;
var nextDT=RoundUpFuzzy(现在,TimeSpan.frommins(1));
var ms=下一次减去(现在);
Console.WriteLine(“现在:+Now.ToString(“HH:mm:ss.fff”)+”nextDT:+nextDT.ToString(“HH:mm:ss.fff”)+“waitMS:+ms.total毫秒”);
timersTimer=new System.Timers.Timer();
timersTimer.Interval=(int)ms.total毫秒;
timersTimer.appeased+=测试计时器;
timersTimer.AutoReset=false;
timersTimer.Enabled=true;
}
公共无效测试线程计时器(对象o)
{
var now=DateTime.UtcNow;
var nextDT=RoundUpFuzzy(现在,TimeSpan.frommins(1));
var ms=下一次减去(现在);
Console.WriteLine(“现在:+Now.ToString(“HH:mm:ss.fff”)+”nextDT:+nextDT.ToString(“HH:mm:ss.fff”)+“waitMS:+ms.total毫秒”);
threadingTimer=new System.Threading.Timer(new System.Threading.TimerCallback(Test_threadingTimer),null,ms,TimeSpan.frommilluses(-1));
}
公共无效测试
{
对于(int i=0;i<10;i++)
{
var now=DateTime.UtcNow;
var nextDT=RoundUpFuzzy(现在,TimeSpan.frommins(1));
var waitTS=nextDT.Subtract(现在);
Console.WriteLine(“现在:+Now.ToString(“HH:mm:ss.fff”)+”nextDT:+nextDT.ToString(“HH:mm:ss.fff”)+“waitMS:+waitTS.total毫秒”);
系统线程线程睡眠(waitTS);
}
}
DateTime RoundUpFuzzy(DateTime dt,TimeSpan d)
{
int n=1;
如果(dt.毫秒>900)
n=2;
返回新的日期时间(((dt.Ticks+(d.Ticks*n)-1)/d.Ticks)*d.Ticks);
}
}

为了避免这些问题,我建议使用Quartz.Net()。它很容易使用,线程和计时器都有一个,所以你不能期望有比这更好的


对于精确的时间测量,必须使用,因为这是基于高分辨率频率。

检查实际时间,如果几毫秒内没有时间,请添加另一个计时器回调?或者如果它真的很近,某种旋转等待?请注意,计时精度并不精确;计时器或时钟,或两者都可以:几毫秒就可以关闭。你用的是什么计时器?@MartinMulder你有完整的密码:我在使用睡眠。你的
RoundUpFuzzy
方法的目的是什么?@MongZhu将时间取整到下一个精确的1分钟,除非我们离它已经不到100毫秒了。在这种情况下,四舍五入到更远处的下一分钟。过去是这样,但现在不再是这样了。某些现代Windows操作系统不再存在此问题。@ManInMoon您是否有提供此信息的链接?因为我只能在MSDN上找到15毫秒的分辨率,我很有兴趣阅读它。@ManInMoon它明确指出某些硬件可以管理它,但您需要添加一些代码来强制整个系统使用这个特殊的时钟。因此,通过使用System.trheading.thread.sleep,您仍然停留在15 msMartin。你说得对。在我的真实应用程序中,我实际上使用的是system.threading.thread.sleep。这是精确的。见编辑的问题
public partial class Form1 : Form
{
    System.Threading.Timer threadingTimer;
    System.Timers.Timer timersTimer;

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        Test_Sleep();
        Test_ThreadingTimer("");
        Test_TimersTimer("", null);
    }

    public void Test_TimersTimer(object o, System.Timers.ElapsedEventArgs e)
    {
        var now = DateTime.UtcNow;
        var nextDT = RoundUpFuzzy(now, TimeSpan.FromMinutes(1));
        var ms = nextDT.Subtract(now);
        Console.WriteLine("Now: " + now.ToString("HH:mm:ss.fff") + " nextDT: " + nextDT.ToString("HH:mm:ss.fff") + " waitMS: " + ms.TotalMilliseconds);
        timersTimer = new System.Timers.Timer();
        timersTimer.Interval = (int)ms.TotalMilliseconds;
        timersTimer.Elapsed += Test_TimersTimer;
        timersTimer.AutoReset = false;
        timersTimer.Enabled = true;
    }

    public void Test_ThreadingTimer(object o)
    {
        var now = DateTime.UtcNow;
        var nextDT = RoundUpFuzzy(now, TimeSpan.FromMinutes(1));
        var ms = nextDT.Subtract(now);
        Console.WriteLine("Now: " + now.ToString("HH:mm:ss.fff") + " nextDT: " + nextDT.ToString("HH:mm:ss.fff") + " waitMS: " + ms.TotalMilliseconds);
        threadingTimer = new System.Threading.Timer(new System.Threading.TimerCallback(Test_ThreadingTimer), null, ms, TimeSpan.FromMilliseconds(-1));
    }

    public void Test_Sleep()
    {
        for (int i = 0; i < 10; i++)
        {
            var now = DateTime.UtcNow;
            var nextDT = RoundUpFuzzy(now, TimeSpan.FromMinutes(1));
            var waitTS = nextDT.Subtract(now);
            Console.WriteLine("Now: " + now.ToString("HH:mm:ss.fff") + " nextDT: " + nextDT.ToString("HH:mm:ss.fff") + " waitMS: " + waitTS.TotalMilliseconds);
            System.Threading.Thread.Sleep(waitTS);
        }
    }

    DateTime RoundUpFuzzy(DateTime dt, TimeSpan d)
    {
        int n = 1;
        if (dt.Millisecond > 900)
            n = 2;
        return new DateTime(((dt.Ticks + (d.Ticks * n) - 1) / d.Ticks) * d.Ticks);
    }
}