我一直在使用C#做一个小游戏,而在另一台PC上测试游戏时,我遇到了一些奇怪的时间问题。
我已根据自上次游戏循环后的时间更新本游戏中设置的所有内容,在大多数情况下应该是这样,但在第二台PC上,所有内容都已关闭。
我发现问题与使用FromTicks()
方法创建TimeSpan有关。我使用以下代码进行了一些测试:
class Program
{
static void Main(string[] args)
{
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1));
sw.Stop();
TimeSpan t = TimeSpan.FromTicks(sw.ElapsedTicks);
Console.WriteLine(t.ToString());
Console.WriteLine(sw.Elapsed.ToString());
Console.ReadKey();
}
}
在我的主电脑上,我运行了这个程序并获得了以下内容:
00:00:00.3528353 00:00:00.9856987
我完全没想到的东西。我认为第二个结果非常不准确,但第一个结果很好。
然后我在另一台PC上运行了相同的程序并得到了这个:
00:03:20.6866734 00:00:00.998287
我非常震惊。
我的问题不是我如何解决这个问题,我已经决定使用第二种方法,因为它足够准确......相反,我要求启发。
怎么会这样?为什么第一个结果如此不准确?为什么这在另一台机器上变化很大?
我检查msdn以防我使用该方法时出错,但是那里的示例显示我的结果应该是不可能的......
注意:
我认为CMOS电池正在死亡/死亡,这是一个因素吗?
答案 0 :(得分:6)
Timespan的Ticks和Stopwatch的Ticks是不同的。要进行协调,请使用Stopwatch Elapsed属性,该属性可根据机器的刻度正确转换为TimeSpan。
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1));
sw.Stop();
// don't load a TimeSpan with ElapsedTicks, these have diff frequency,
// call Elapsed instead to get TimeSpan.
TimeSpan t = sw.Elapsed;
Console.WriteLine(t.ToString());
Console.ReadKey();
或者,您当然可以自己划分频率等,但这需要做更多的工作。主要的一点是你不应该把TimeSpan的Ticks和Stopwatch的Ticks一样考虑。
相关主题:What are timer ticks, the unit used by Stopwatch.ElapsedTicks
答案 1 :(得分:6)
摘要:秒表的频率在不同的硬件上可能会有所不同,这意味着刻度线(其间隔基于频率)具有不同的大小(并且与刻度的大小不同)时间跨度和日期时间对象)。
简而言之,请直接使用Elapsed
属性:
TimeSpan t = sw.Elapsed;
...或者如果您需要执行计算,请使用Ticks
的{{1}}属性:
Elapsed
带引用的长版本:
http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.elapsedticks.aspx是经过时间刻度的msdn页面。值得注意的是:
此属性表示基础中经过的刻度数 计时器机制。刻度是最小的时间单位 秒表计时器可以测量。使用频率字段转换 ElapsedTicks值为几秒钟。
从频率字段的页面:
定时器频率表示定时器精度和分辨率。对于 例如,每秒200万个滴答的定时器频率等于a 定时器分辨率为每个刻度500纳秒。换句话说,因为 一秒等于10亿纳秒,定时器频率为2 每秒百万次刻度相当于每1百万次刻度 十亿纳秒,可以进一步简化为每500个1个刻度 毫微秒。
频率值取决于基础时间的分辨率 机制。如果安装的硬件和操作系统支持a 高分辨率性能计数器,然后频率值反映 那个柜台的频率。否则,频率值基于 关于系统定时器频率。
因为秒表频率取决于安装的硬件和 操作系统,频率值保持不变 系统正在运行。
所以秒表的频率基本上可以在不同的硬件上有所不同,这意味着刻度线的大小不同(与时间跨度和日期时间对象中的刻度不同)。
有趣的是,您已经在使用Elapsed属性StopWatch,它为您提供了一个时间跨度。 sw.Elapsed是一个TimeSpan,它可能是你在尝试获取TimeSpan对象时所追求的。如果你想使用刻度线,你可以使用这个TimeSpan的Ticks属性。
或者,您可以使用ElapsedMilliseconds返回long。
答案 2 :(得分:0)
仅为您提供信息......我测试了它,如果您绝对想要使用" FromTicks"这就是如何做到的。但如果我是你,我会跟随James Michael Hare的建议。
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(1));
sw.Stop();
// don't load a TimeSpan with ElapsedTicks, these have diff frequency,
// call Elapsed instead to get TimeSpan.
TimeSpan t1 = sw.Elapsed;
Debug.Print("Millisecs: " + t1.TotalMilliseconds);
// TimeSpan.Elapsed Code
//if (!SafeNativeMethods.QueryPerformanceFrequency(out Stopwatch.Frequency))
//{
// Stopwatch.IsHighResolution = false;
// Stopwatch.Frequency = 10000000L;
// Stopwatch.tickFrequency = 1.0;
//}
//else
//{
// Stopwatch.IsHighResolution = true;
// Stopwatch.tickFrequency = 10000000.0;
// Stopwatch.tickFrequency /= (double)Stopwatch.Frequency;
//}
//public TimeSpan Elapsed
//{
// [__DynamicallyInvokable]
// get
// {
// return new TimeSpan(this.GetElapsedDateTimeTicks());
// }
//}
//private long GetElapsedDateTimeTicks()
//{
// long rawElapsedTicks = this.GetRawElapsedTicks();
// if (Stopwatch.IsHighResolution)
// return (long)((double)rawElapsedTicks * Stopwatch.tickFrequency);
// return rawElapsedTicks;
//}
TimeSpan t2;
if (Stopwatch.IsHighResolution)
{
t2 = TimeSpan.FromTicks((long)((double)sw.ElapsedTicks * ((double)10000000.0 / (double)Stopwatch.Frequency)));
}
else
{
t2 = TimeSpan.FromTicks(sw.ElapsedTicks);
}
Debug.Assert(t1.TotalMilliseconds == t2.TotalMilliseconds); // true,
return;