C#等待Task.Delay(1000);只需640毫秒即可返回

时间:2016-04-19 17:48:34

标签: c# wpf

所以,这很容易解释,但我已经搜索过,找不到任何有相同问题的人。我的问题起源于一项长期的周期性任务,这项任务比我想要的更频繁。似乎每个Task.Delay()我创建并等待返回约为我在ms中指定的延迟的65%。

问题归结为下面的代码行返回大约640-660ms(根据visual studio。我在这行代码上设置了一个断点,然后跟着它编写了一个断点,它说有多长已经通过了):

await Task.Delay(1000); 

在另外两台机器上,IDENTICAL代码库运行正常。不仅是上面这个简单的陈述,还有周期性的任务。是否存在会影响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再次为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,我仍然可以从我的秒表获得大约130毫秒.ElapsedMilliseconds ...但这是奇怪的事情。如果我还更新DateTime.Now()的显示,它们会增加大约200ms(或稍微多一点),这是我所期望的。什么?!?! enter image description here

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();
    }
}

2 个答案:

答案 0 :(得分:2)

我根据到目前为止进行的实验得出一个猜测答案。

Stopwatch班级使用Windows "performance counter"。我经常读到在某些系统上它会返回不准确的数据。这似乎发生在较旧的硬件和/或较旧的操作系统版本中。

例如,时间可以根据您正在执行的核心跳转。这可能不是问题,因为你的时间一直是关闭的。但这是这类时间数据出现问题的一个例子。

我猜Visual Studio也使用Stopwatch

这也适用于问题只发生在您的机器上的事实。其他机器可能有不同的时间硬件。

试试这个:

var sw = Stopwatch.StartNew();
var startDateTime = DateTime.UtcNow;

Thread.Sleep(200);

sw.Stop();
var endDateTime = DateTime.UtcNow;

并发布结果。我的预测是Stopwatch版本错误,基于DateTime的版本显示略超过200毫秒。

据我所知,Windows内核使用DateTime.UtcNow用于自己定时器和延迟的时间源。 AFAIK是一种硬件中断,默认情况下,它以60Hz的速率滴答,并使定时器以该速率更新全局时间变量。这意味着,即使DateTime.UtcNow出错,也应与Thread.Sleep保持一致。但我们知道DateTime.UtcNow是正确的。否则你会注意到系统时间的显着漂移。

也许您可以尝试禁用为Windows提供高频计数器的硬件。 Stopwatch.IsHighResolution现在应该返回true,并且在禁用此硬件时应该变为false。在我的机器上,它在设备管理器中称为“HPET”。

答案 1 :(得分:0)

为了解决这个问题,如果其他人遇到类似的问题,我找到了解决问题的方法。大约一个月前,我的Windows 7' Aero'效果开始非常缓慢。在寻找该问题的解决方案时,我发现了以下内容:

http://www.tomshardware.com/forum/57307-63-slow-motion-aero-transitions

我使用的解决方案是在上面的链接中:

以管理员身份运行CMD。输入" bcdedit / set useplatformclock true"然后按Enter键(不带引号)。重新启动计算机,我的问题得到解决。

我不完全理解该命令的内部运作,所以如果有人想详细说明,请做。但我知道它不仅解决了我的慢速空气动力效果,而且我的秒表计时器现在已经出现了!

感谢你们的努力,我很感激!

加里