C# 任务延迟与线程睡眠解决精度

C# 任务延迟与线程睡眠解决精度,c#,multithreading,asynchronous,sleep,C#,Multithreading,Asynchronous,Sleep,我需要在一段特定的时间后执行一个函数,因此我使用这段代码 _start = DateTime.Now; await Task.Delay(_app.Settings.AudioFileStartVarianz.BaseSpan).ContinueWith(x => { Console.WriteLine(DateTime.Now - _start); }); 假设我想等待0.04秒。我现在的问题是它不够精确。调用函数5次后,我得

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

_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

两个调用
线程.Sleep
任务.Delay
之间的区别在于
线程.Sleep
调用操作系统方法来睡眠线程和
任务。Delay
创建一个
计时器来模拟延迟

这些电话有效地

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中的计时器分辨率低是出了名的——大约有15毫秒的误差。我想正是因为这样,你才有了结果


坏消息是,正如您所说,休眠线程不是异步的,所以要获得异步,您需要接受计时器解析错误。我认为没有任何明智的方法可以避免它。

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

多媒体计时器服务允许应用程序安排计时器事件 以硬件可能的最大分辨率(或精度) 站台。这些多媒体定时器服务允许您安排定时器 事件的分辨率高于其他计时器服务

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

例如,它可以是

编辑代码简化:

    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");
    }
不要试图检查计时器是否与日期时间正确同步。根据系统的不同,其精度大约为15或16毫秒


进一步阅读:

不是Windows计时器将分辨率限制在15毫秒左右。相反,Windows计时器周围的.NET包装器施加了该限制。@JimMischel-我的理解是,该限制是操作系统的核心(设置为1/64秒或15.625秒),但可以更改。读一读。改变它的问题是功耗,因此便携式设备的电池寿命。是的,我读过。但至少在我使用过的每台台式机和笔记本电脑上,如果我创建一个1毫秒的计时器队列计时器,我会得到1毫秒。多媒体计时器已经被弃用十年了。不要使用它们。计时器队列计时器更灵活,使用更少的系统资源,并提供与多媒体计时器相同的精度。有关实现和示例,请参见。或者,使用线程池计时器。但是请关掉多媒体定时器。