Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/loops/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何制作精确的十进制计时器?_C#_Winforms_Timer - Fatal编程技术网

C# 如何制作精确的十进制计时器?

C# 如何制作精确的十进制计时器?,c#,winforms,timer,C#,Winforms,Timer,我对这件事感到很沮丧 我有一个名为timer1的计时器、一个名为TimeElapsedTextBox的文本框和一个名为TimeTakenToFinish的双变量 计时器每1秒滴答响1000毫秒 在文本框中,我希望它以以下格式显示时间: Seconds.PartsOfSecond 以下是滴答声事件: private void timer1_Tick(object sender, EventArgs e) { TimeTakenToFinish += (double)timer1.Interv

我对这件事感到很沮丧

我有一个名为timer1的计时器、一个名为TimeElapsedTextBox的文本框和一个名为TimeTakenToFinish的双变量 计时器每1秒滴答响1000毫秒 在文本框中,我希望它以以下格式显示时间:

Seconds.PartsOfSecond
以下是滴答声事件:

private void timer1_Tick(object sender, EventArgs e)
{
  TimeTakenToFinish += (double)timer1.Interval / 10000;
  TimeElapsedTextBox.Text = TimeTakenToFinish;
}
它实际上是以我想要的方式显示在文本框中, 但是它没有正确地计数。。 我的意思是,它不到一秒钟


你能告诉我怎么修理这个吗

您的问题在于对操作系统工作方式的误解。当然,您可以将间隔设置为1000毫秒,但不能期望它实际上每秒钟都在滴答作响。您正在Windows上运行代码,而不是硬实时或软实时操作系统

另外,您还应该知道,计时器的分辨率是有限的,从今天起,仅限于系统计时器的精度,大约为15毫秒

您不能期望您的代码在那种环境中以确定性的方式执行。在任何时候,操作系统都可以先发制人地将您踢出CPU并开始执行另一项任务

你根本无法得到你想要的准确度,尽管我会问;真的需要吗?也许没有,但你还没有告诉我们你在这里想要完成什么,所以谁知道呢

而且,这是错误的:

TimeTakenToFinish += (double)timer1.Interval / 10000;
Interval是一个属性,用于告诉计时器触发滴答事件的大致频率。实际上,您并不是在测量任何东西,您也可以每次向计数器添加1000.0/10000

如果您需要更高的精度,请使用StopWatch类,该类使用CPU的高性能计时器(如果可用)。您仍然可以使用计时器根据秒表的当前运行值定期更新UI,即

void timer1_Tick(...)
{
    var totalSeconds = _someStopwatch.ElapsedMilliseconds / 1000.0;
    TimeElapsedTextBox.Text = totalSeconds.ToString();
}

这里的问题是对操作系统工作方式的误解。当然,您可以将间隔设置为1000毫秒,但不能期望它实际上每秒钟都在滴答作响。您正在Windows上运行代码,而不是硬实时或软实时操作系统

另外,您还应该知道,计时器的分辨率是有限的,从今天起,仅限于系统计时器的精度,大约为15毫秒

您不能期望您的代码在那种环境中以确定性的方式执行。在任何时候,操作系统都可以先发制人地将您踢出CPU并开始执行另一项任务

你根本无法得到你想要的准确度,尽管我会问;真的需要吗?也许没有,但你还没有告诉我们你在这里想要完成什么,所以谁知道呢

而且,这是错误的:

TimeTakenToFinish += (double)timer1.Interval / 10000;
Interval是一个属性,用于告诉计时器触发滴答事件的大致频率。实际上,您并不是在测量任何东西,您也可以每次向计数器添加1000.0/10000

如果您需要更高的精度,请使用StopWatch类,该类使用CPU的高性能计时器(如果可用)。您仍然可以使用计时器根据秒表的当前运行值定期更新UI,即

void timer1_Tick(...)
{
    var totalSeconds = _someStopwatch.ElapsedMilliseconds / 1000.0;
    TimeElapsedTextBox.Text = totalSeconds.ToString();
}

不要使用计时器,而是使用DateTime.Now记录开始时间,然后从开始时间减去当前时间DateTime.Now。这将为您提供更精确的计时器,因为它使用的是系统时钟,而不受CPU性能的影响太大

或者,您也可以使用System.Diagnostics.Stopwatch来完成此操作


您仍然可以使用间隔小于1秒的普通计时器来刷新显示时间的标签。

不要使用计时器,而是使用DateTime记录开始时间。不时从开始时间减去当前时间DateTime。Now。这将为您提供更精确的计时器,因为它使用的是系统时钟,而不受CPU性能的影响太大

或者,您也可以使用System.Diagnostics.Stopwatch来完成此操作


您仍然可以使用间隔不到一秒的普通计时器刷新显示时间的标签。

不要只在每个刻度上添加请求的间隔。更确切地说,你应该检查实际已经花了多少时间,并把这个数字添加到TimeTaToFoFiSim.如果你唯一的问题是你需要更多的精度,考虑Syt.Debug,S秒表类。它有一个静态属性IsHighResolution,其真实值表示处理器支持高分辨率计时器。有关更多详细信息,请参阅。您将希望在秒表上使用.eassed和任何.ElapsedXXX属性。您当前使用的方法会在每次滴答声中产生一些舍入误差,因为计时器不能保证完全按照您告诉它的速率启动。这将导致你的时间离现实越来越远。使用增量方法记录starttime,然后每个勾号显示starttime-currenttime以保持准确。或者更好:使用
这个类是用来做你想做的。@Kivin我认为Vexe无论如何都不需要高分辨率。对于大多数在表格上测量和显示的东西来说,一块普通的秒表是合适的。我不认为他在计算CPU周期;他的问题是,他使用的方法是假设计时器精确地每1000毫秒触发一次,而实际上没有。使用这种方法,即使是高分辨率计时器最终也会漂移。Windows和大多数操作系统都不是RT-OS,甚至那些都会随波逐流eventually@EdS.一切都很好,但你不需要这么高的精确度。因此,即使出于某种原因,IsHighResolution返回false,它仍然足够精确,可以像Vexe所做的那样测量CPS/WPM。假设Vexe现在有了这些答案,至少能够测量一分钟而不会漂移几毫秒,每个刻度只需计算一分钟的击键次数,这将得到CPS/WPM分数+/-.01。谁在乎测量值是否“意外”为00:01:00.015?这不会影响分数。如果你在测量F1圈数,那么你需要更精确一点。不要只在每个刻度上加上要求的间隔。更确切地说,你应该检查实际已经花了多少时间,并把这个数字添加到TimeTaToFoFiSim.如果你唯一的问题是你需要更多的精度,考虑Syt.Debug,S秒表类。它有一个静态属性IsHighResolution,其真实值表示处理器支持高分辨率计时器。有关更多详细信息,请参阅。您将希望在秒表上使用.eassed和任何.ElapsedXXX属性。您当前使用的方法会在每次滴答声中产生一些舍入误差,因为计时器不能保证完全按照您告诉它的速率启动。这将导致你的时间离现实越来越远。使用增量方法记录starttime,然后每个勾号显示starttime-currenttime以保持准确。或者更好:使用这个类,它可以做你想做的事情。@Kivin我认为Vexe无论如何都不需要高分辨率。对于大多数在表格上测量和显示的东西来说,一块普通的秒表是合适的。我不认为他在计算CPU周期;他的问题是,他使用的方法是假设计时器精确地每1000毫秒触发一次,而实际上没有。使用这种方法,即使是高分辨率计时器最终也会漂移。Windows和大多数操作系统都不是RT-OS,甚至那些都会随波逐流eventually@EdS.一切都很好,但你不需要这么高的精确度。因此,即使出于某种原因,IsHighResolution返回false,它仍然足够精确,可以像Vexe所做的那样测量CPS/WPM。假设Vexe现在有了这些答案,至少能够测量一分钟而不会漂移几毫秒,每个刻度只需计算一分钟的击键次数,这将得到CPS/WPM分数+/-.01。谁在乎测量值是否“意外”为00:01:00.015?这不会影响分数。如果要测量F1圈数,则需要更高的精度。DateTime.Now的分辨率约为15毫秒,与计时器的分辨率大致相同。如果您的代码对CPU性能敏感,我看不出如何调用DateTime.Now会比使用计时器更好。您的代码没有运行,使用哪种方法有什么关系?@EdS。当您记录开始时间和每次更新时,例如在表单中打勾,您将显示增量,例如开始时间-当前时间,您的关闭时间将永远不会超过您所说的15毫秒。如果您的代码没有运行,请从记录的日期时间中减去当前时间。现在,你不会得到准确的答案。您建议的工作的唯一方法是坐在一个循环中,使用尽可能多的CPU将当前时间与记录的时间进行比较。坏主意。@RobIII:是的,没错。我是说OP的目标是每X毫秒运行一些代码。@Eds啊,我不知道。我假设Stopwatch类使用更精确的方法。我认为重点是你不应该通过滴答事件来计数。您应该只显示自时钟开始时间以来经过的时间。DateTime.Now的分辨率为~15ms,与计时器的分辨率大致相同。如果您的代码对CPU性能敏感,我看不出如何调用DateTime.Now会比使用计时器更好。您的代码没有运行,使用哪种方法有什么关系?@EdS。当您记录开始时间和每次更新时,例如在表单中打勾,您将显示增量,例如开始时间-当前时间,您的关闭时间将永远不会超过您所说的15毫秒。如果您的代码没有运行,请从记录的日期时间中减去当前时间。现在,你不会得到准确的答案。您建议的工作的唯一方法是坐在一个循环中,使用尽可能多的CPU将当前时间与记录的时间进行比较。坏主意。@RobIII:是的,没错。我是说OP的目标是每X毫秒运行一些代码。@Eds啊,我不知道。我假设Stopwatch类使用更精确的方法。我认为重点是你不应该被计数
g通过滴答声事件。您应该只显示自时钟开始时间以来经过的时间。实际上,当我除以1000时,如下所示:TimeTakenToFinish+=doubletimer1.Interval/1000;我在文本框中得到了精确的秒数。回答你的问题,是的,我需要它是准确的。。为什么?因为我需要时间来计算打字程序的CPS和WPM,时间越精确,两者就越精确。@VeXe:不,你认为你得到的结果是准确的。实际上,每次计时器的滴答声事件被触发时,您只需向计数器添加1000.0/10000。Interval属性不是两次计时之间经过了多少时间的记录,而是在启动计时器之前设置的静态值。你没有测量任何东西。用秒表精确计时,这就是它的用途。@VeXe是的,我需要它精确。。为什么?因为我需要时间来计算打字程序的CPS和WPM,时间越精确,两者就越精确。很好,但是你需要把准确度放在这里。为此,1毫秒甚至10毫秒或100毫秒的分辨率就足够了;除非你的测量值和你的一样漂移。此外,测量周期越长,1或2位十进制数字CPS/WPM结果的精度就越低。想想看,实际上,当我像这样除以1000:TimeTakenToFinish+=doubletimer1.Interval/1000;我在文本框中得到了精确的秒数。回答你的问题,是的,我需要它是准确的。。为什么?因为我需要时间来计算打字程序的CPS和WPM,时间越精确,两者就越精确。@VeXe:不,你认为你得到的结果是准确的。实际上,每次计时器的滴答声事件被触发时,您只需向计数器添加1000.0/10000。Interval属性不是两次计时之间经过了多少时间的记录,而是在启动计时器之前设置的静态值。你没有测量任何东西。用秒表精确计时,这就是它的用途。@VeXe是的,我需要它精确。。为什么?因为我需要时间来计算打字程序的CPS和WPM,时间越精确,两者就越精确。很好,但是你需要把准确度放在这里。为此,1毫秒甚至10毫秒或100毫秒的分辨率就足够了;除非你的测量值和你的一样漂移。此外,测量周期越长,1或2位十进制数字CPS/WPM结果的精度就越低。想想看。