任务延迟与线程睡眠分辨率准确度

时间:2016-06-22 11:46:27

标签: c# multithreading asynchronous sleep

我需要在特定的时间后执行一个函数,因此我使用此代码。

_start = DateTime.Now;
await Task.Delay(_app.Settings.AudioFileStartVarianz.BaseSpan).ContinueWith(x => 
        {
            Console.WriteLine(DateTime.Now - _start);

        });

让我们说我想要等待0.04秒。我现在的问题是它的工作不够精确。在调用该函数5次后,我得到以下输出:

  • 00:00:00.0414220
  • 00:00:00.0536098
  • 00:00:00.0507841
  • 00:00:00.0467757
  • 00:00:00.0425790

如果我使用此代码,它的工作方式会更好

        _start = DateTime.Now;
        Thread.Sleep(_app.Settings.AudioFileStartVarianz.BaseSpan);
        Console.WriteLine(DateTime.Now - _start);
  • 00:00:00.0405879
  • 00:00:00.0404284
  • 00:00:00.0402117
  • 00:00:00.0404908
  • 00:00:00.0409088

但是现在我遇到了问题,该函数没有异步运行,有什么不好因为我正在播放音频文件(NAudio)。

我有什么想法可以在这里等待异步,以便我的音频文件没有停止?

KR Manuel

2 个答案:

答案 0 :(得分:3)

两次通话之间的差异Thread.Sleep& Task.DelayThread.Sleep调用OS方法来休眠线程,Task.Delay创建Timer来模拟延迟。

电话有效......

private static extern int WaitOneNative(SafeHandle waitableSafeHandle, uint millisecondsTimeout, bool hasThreadAffinity, bool exitContext);

...和...

promise.Timer = new Timer(state => ((DelayPromise)state).Complete(), promise, millisecondsDelay, Timeout.Infinite);

...分别

现在Windows中的计时器出了名的低分辨率 - 大约15ms的错误。我认为因为这样你才能得到你的结果。

坏消息是,正如你所说,休眠线程不是异步的,所以为了获得异步,你需要接受定时器分辨率错误。我不认为有任何理智的方法可以避免它。

答案 1 :(得分:1)

要获得准确的计时器,您应该使用multimedia timer

  

多媒体计时器服务允许应用程序安排计时器事件   具有最高分辨率(或精度)的硬件   平台。这些多媒体计时器服务允许您安排计时器   比其他计时器服务更高分辨率的事件。

你可以在那里找到一个实现:

http://www.codeproject.com/Articles/5501/The-Multimedia-Timer-for-the-NET-Framework

因此,对于您的示例,它可能类似于

编辑代码简化:

    Multimedia.Timer mmTimer = new Multimedia.Timer(new Container())
    {
        Mode = Multimedia.TimerMode.OneShot,
        Period = 40,
        Resolution = 1,
        SynchronizingObject = this
    };
    mmTimer.Tick += new System.EventHandler(this.mmTimer_Tick);
    startTime = DateTime.Now;
    mmTimer.Start();

    private void mmTimer_Tick(object sender, System.EventArgs e)
    {           
        MessageBox.Show("ticks after 40ms");
    }

请勿尝试使用DateTime检查计时器是否正确滴答。现在,精确度大约为15或16 ms,具体取决于系统。

进一步阅读:http://www.nullskull.com/articles/20021111.asp