所以,这很容易解释,但是我已经搜索了一下,没有找到有相同问题的人。我的问题源于一个长期定期任务,它比我想要的频率更频繁地运行。似乎我创建和等待的每个Task.Delay()都会在指定的延迟时间的约65%处返回。
问题归结为以下代码行大约在640-660ms内返回(根据Visual Studio的显示。我在这行代码和随后的一行代码上设置了断点,并且它说已经过去了那么长时间):
await Task.Delay(1000);
在另外两台机器上,完全相同的代码库都可以正常运行。不仅上述简单语句如此,周期性任务也是如此。是否有某处设置会影响Task.Delay(int millisecondsDelay)?时钟类型、时钟速度、任何东西、系统时钟?我很迷惑...
编辑:
在下面的片段中,EtMilliseconds的值在130-140毫秒之间,大约是上面期望持续时间的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 再次变为约131毫秒。使用 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不行),时间要么是131ms,要么是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, 0, 0, 0, 200);
dispatcherTimer.Start();
etWatch.Restart();
}
}
Task.Delay
开始和结束之间的时间?如果你想要准确,应该使用一个Stopwatch
实例。同时确保.Delay
被正确地等待,并且调用栈一直使用async/await
模式。还要确保你的StopWatch
的作用域被正确设置,你不希望另一个线程可以更改共享实例。 - IgorThread.Sleep
吗?只是为了尝试一下。我肯定在我的机器上无法复现 :-/ - Jcl