微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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”.

原文地址:https://www.jb51.cc/csharp/93512.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐