C#等待Task.Delay(1000);只需640ms才能返回
所以,这是很简单的解释,但我已经搜索,找不到有同样问题的人.我的问题起源于一个长期的定期任务,比我想要的更频繁.似乎每个Task.Delay()我创建并等待返回大约65%的延迟我指定的ms.
这个问题归结为以下代码:大概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”. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |