Task Delay vs Thread Sleep Resolution Accuracy

冷暖自知 提交于 2019-12-10 23:59:43

问题


i need to execute a function after a specific amount of time, therefore i use this code.

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

        });

Lets say i want to wait for exactly 0.04 seconds. My problem now is that it's not working precise enough. I get following output after calling the function 5 times:

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

if i use this code it works way better

        _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

But now i have the problem, that the function is not running asynchronous, what is bad because i am playing an audio file (NAudio).

Any ideas how i can here wait async, so that my audio file is not stopping?

KR Manuel


回答1:


The difference between the two calls, Thread.Sleep & Task.Delay, is that Thread.Sleep calls an OS method to sleep the thread and Task.Delay creates a Timer to simulate the delay.

The calls are effectively...

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

...and...

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

...respectively.

Now timers in windows are notoriously low resolution - with a 15ms error or so. I think it's because of this that you're getting your results.

The bad news is that sleeping the thread is not asynchronous, as you stated, so to get asynchrony you need to accept the timer resolution error. I don't think that there is any sane way for you to avoid it.




回答2:


To get an accurate timer you should use a multimedia timer :

Multimedia timer services allow applications to schedule timer events with the greatest resolution (or accuracy) possible for the hardware platform. These multimedia timer services allow you to schedule timer events at a higher resolution than other timer services.

You can find an implementation there :

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

So for your example it can be something like

EDIT code simplified :

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

Dont try to check if the timer ticks correctly with DateTime.Now the precision of this is around 15 or 16 ms depending on the system.

Further reading : http://www.nullskull.com/articles/20021111.asp



来源:https://stackoverflow.com/questions/37967123/task-delay-vs-thread-sleep-resolution-accuracy

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!