这个问题归结为以下代码:大概640-660ms的代码返回(根据visual studio,我在这行代码中设置了一个断点,并且这个代码已经过了多久)
await Task.Delay(1000);
在另外两台机器上,IDENTICAL代码库运行正常.不仅仅是上面这个简单的陈述,而且是周期性的任务.有什么地方会影响Task.Delay(int millisecondsDelay)吗?刻度类型,时钟速度,任何东西,系统时钟???我很茫然…
编辑:
在下面的代码段中,EtMilliseconds的大小从130-140ms是相同的.上述预期持续时间的65%. (除了第一次进入while()是不相关的).
Long EtMilliseconds; Stopwatch etWatch = new Stopwatch(); etWatch.Restart(); while (true) { EtMilliseconds = etWatch.ElapsedMilliseconds; taskDelay = Task.Delay(200); etWatch.Restart(); await taskDelay; }
编辑2:
以下代码会导致EtMilliseconds再次为131ms左右.使用Thread.Sleep似乎没有影响…
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void button_Click(object sender,RoutedEventArgs e) { long EtMilliseconds; Stopwatch etWatch = new Stopwatch(); etWatch.Restart(); while (true) { EtMilliseconds = etWatch.ElapsedMilliseconds; label.Content = EtMilliseconds.ToString(); etWatch.Restart(); Thread.Sleep(200); } } }
这个代码段是一样的,但使用Task.Delay(200).这一个正确地更新了GUI标签(Thread.Sleep没有),它是131或140ms.总是…
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private async void button_Click(object sender,RoutedEventArgs e) { Task taskDelay; long EtMilliseconds; Stopwatch etWatch = new Stopwatch(); etWatch.Restart(); while (true) { EtMilliseconds = etWatch.ElapsedMilliseconds; label.Content = EtMilliseconds.ToString(); taskDelay = Task.Delay(200); etWatch.Restart(); await taskDelay; } } }
编辑3:
使用DispatcherTimer,我仍然从我的Stopwatch.ElapsedMilliseconds大约130ms …但这是一个奇怪的事情.如果我还更新了DateTime.Now()的显示,它们会增加大约200ms(或稍微更多),这是我期望的.什么?
public partial class MainWindow : Window { public long etMilliseconds; public Stopwatch etWatch; public MainWindow() { InitializeComponent(); this.DataContext = this; } // System.Windows.Threading.DispatcherTimer.Tick handler // // Updates the current seconds display and calls // InvalidateRequerySuggested on the CommandManager to force // the Command to raise the CanExecuteChanged event. private void dispatcherTimer_Tick(object sender,EventArgs e) { // Updating the Label which displays the current second tBoxCurrTime.Text += DateTime.Now.ToString("yyyy_MMM_dd-hh:mm:ss.fff_tt") + "\n"; tBoxMilliSecElapsed.Text += etWatch.ElapsedMilliseconds + "\n"; etWatch.Restart(); // Forcing the CommandManager to raise the RequerySuggested event CommandManager.InvalidateRequerySuggested(); } private void button_Click(object sender,RoutedEventArgs e) { etWatch = new Stopwatch(); // DispatcherTimer setup DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer(); dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick); dispatcherTimer.Interval = new TimeSpan(0,200); dispatcherTimer.Start(); etWatch.Restart(); } }
解决方法
Stopwatch类使用Windows “performance counter”.我经常读到在某些系统上它返回不准确的数据.这似乎发生在较旧的硬件和/或较旧的操作系统版本.
例如,时间可以根据您正在执行的核心跳转.这可能不是这里的问题,因为你的时间一直在关闭.但这是这种时间数据的问题的一个例子.
我想Visual Studio也使用秒表.
这也符合这个事实,即问题只发生在您的机器上.其他机器可能有不同的时间硬件.
尝试这个:
var sw = Stopwatch.StartNew(); var startDateTime = DateTime.UtcNow; Thread.Sleep(200); sw.Stop(); var endDateTime = DateTime.UtcNow;
并发布结果.我的预测是,Stopwatch版本是错误的,基于DateTime的版本显示了超过200ms.
据我所知,Windows内核使用DateTime.UtcNow用于自己的计时器和延迟的时间源. AFAIK是一个硬件中断,默认情况下以60Hz为单位,并使定时器以该速率更新全局时间变量.这意味着即使DateTime.UtcNow是错误的,它应该与Thread.Sleep一致.但是我们知道DateTime.UtcNow是对的.否则你会注意到系统时间漂移很大.
也许您可以尝试禁用使用高频计数器提供Windows的硬件. Stopwatch.IsHighResolution应该返回true,当你禁用这块硬件时应该变为false.在我的机器上,它在设备管理器中被称为“HPET”.