简体   繁体   English

更精确的 Thread.Sleep

[英]More precise Thread.Sleep

How can i do Thread.Sleep(10.4166667);?我该怎么做 Thread.Sleep(10.4166667);?

OK i see now that Sleep is not the way to go.好的,我现在知道睡眠不是要走的路。 So i use Timer but timer is also in ms put i need more precise Is there timer with nanosecond accuracy?所以我使用计时器,但计时器也是毫秒,我需要更精确的计时器是否有纳秒精度的计时器?

So you want your thread to sleep precisely for that time and then resume?所以你想让你的线程正好在那段时间休眠然后恢复? Forget about it.忘记它。 This parameter tells the system to wake the Thread after at least this number of milliseconds.此参数告诉系统至少在此毫秒数后唤醒线程。 At least.至少。 And after resuming, the thread could be put to sleep once again in a blink of an eye.恢复后,线程可以在眨眼间再次进入睡眠状态。 That just how Operating Systems work and you cannot control it.这就是操作系统的工作方式,您无法控制它。

Please note that Thread.Sleep sleeps as long as you tell it (not even precisely), no matter how long code before or after takes to execute.请注意,只要您告诉Thread.Sleep休眠(甚至不准确),无论代码在执行之前或之后需要多长时间。

Your question seems to imply that you want some code to be executed in certain intervals, since a precise time seems to matter.您的问题似乎暗示您希望在某些时间间隔内执行某些代码,因为精确的时间似乎很重要。 Thus you might prefer a Timer .因此,您可能更喜欢Timer

To do such a precise sleep you would need to use a real time operating system and you would likely need specialized hardware.要进行如此精确的睡眠,您需要使用实时操作系统,并且可能需要专门的硬件。 Integrity RTOS claims to respond to interrupts in nanoseconds, as do others. Integrity RTOS 声称可以在纳秒内响应中断,其他人也是如此。

This isn't going to happen with C# or any kind of high level sleep call.这不会发生在 C# 或任何类型的高级睡眠调用中。

Please note that the argument is in milliseconds, so 10 is 10 milliseconds.请注意,参数以毫秒为单位,因此 10 是 10 毫秒。 Are you sure you want 10.41 etc milliseconds?您确定要 10.41 等毫秒吗? If you want 10.41 seconds, then you can use 10416.如果你想要 10.41 秒,那么你可以使用 10416。

The input to Thread.Sleep is the number of milliseconds for which the thread is blocked. Thread.Sleep的输入是线程被阻塞的毫秒数。 After that it will be runnable, but you have no influence over when it is actually scheduled.之后它将是可运行的,但您对实际调度的时间没有影响。 Ie in theory the thread could wait forever before resuming execution.即理论上线程在恢复执行之前可以永远等待。

It hardly ever makes sense to rely on specific number of milliseconds here.在这里依赖特定的毫秒数几乎没有任何意义。 If you're trying to synchronize work between two threads there are better options than using Sleep.如果您尝试在两个线程之间同步工作,则有比使用 Sleep 更好的选择

As you already mentioned: You could combine DispatcherTimer with Stopwatch (Making sure the IsHighResolution and Frequency suits your needs).正如您已经提到的:您可以将DispatcherTimer秒表结合使用(确保IsHighResolutionFrequency适合您的需要)。 Start the Timer and the Stopwatch, and on discreet Ticks of the Timer check the exact elapsed time of the stopwatch.启动计时器和秒表,并在计时器的谨慎滴答上检查秒表的确切经过时间。

If you are trying to rate-limit a calculation and insist on using only Thread.Sleep then be aware there is a an underlying kernel pulse rate (roughly 15ms), so your thread will only resume when a pulse occurs.如果您试图对计算进行速率限制并坚持只使用Thread.Sleep那么请注意存在一个底层内核脉冲速率(大约 15 毫秒),因此您的线程只会在脉冲发生时恢复。 The guarantee provided is to "wait at least the specified duration."提供的保证是“至少等待指定的持续时间”。 For example, if you call Thread.Sleep(1) (to wait 1ms), and the last pulse was 13ms ago, then you will end up waiting 2ms until the next pulse comes.例如,如果您调用Thread.Sleep(1) (等待Thread.Sleep(1)毫秒),并且最后一个脉冲是 13 毫秒前,那么您将最终等待 2 毫秒,直到下一个脉冲到来。

The draw synchronization I implemented for a rendering engine does something similar to dithering to get the quantization to the 15ms intervals to be uniformly distributed around my desired time interval.我为渲染引擎实现的绘制同步执行类似于抖动的操作,以将量化到 15 毫秒间隔均匀分布在我想要的时间间隔内。 It is mostly just a matter of subtracting half the pulse interval from the sleep duration, so only half the invocations wait the extra duration to the next 15ms pulse, and half occur early.这主要是从睡眠持续时间中减去一半的脉冲间隔,因此只有一半的调用等待下一个 15ms 脉冲的额外持续时间,而一半会提前发生。

public class TimeSynchronizer {
    //see https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleep
    public const double THREAD_PULSE_MS = 15.6d;//TODO read exact value for your system

    public readonly TimeSpan Min = TimeSpan.Zero;
    public TimeSynchronizer(TimeSpan? min = null) {
        if (min.HasValue && min.Value.Ticks > 0L) this.Min = min.Value;
    }

    private DateTime _targetTimeUtc = DateTime.UtcNow;//you may wish to defer this initialization so the first Synchronize() call assuredly doesn't wait
    public void Synchronize() {
        if (this.Min.Ticks > 0L) {
            DateTime nowUtc = DateTime.UtcNow;
            TimeSpan waitDuration = this._targetTimeUtc - nowUtc;
            //store the exact desired return time for the next inerval
            if (waitDuration.Ticks > 0L)
                this._targetTimeUtc += this.Min;
            else this._targetTimeUtc = nowUtc + this.Min;//missed it (this does not preserve absolute synchronization and can de-phase from metered interval times)

            if (waitDuration.TotalMilliseconds > THREAD_PULSE_MS/2d)
                Thread.Sleep(waitDuration.Subtract(TimeSpan.FromMilliseconds(THREAD_PULSE_MS/2d)));
        }
    }
}

I do not recommend this solution if your nominal sleep durations are significantly less than the pulse rate, because it will frequently not wait at all in that case.如果您的标称睡眠持续时间明显小于脉搏率,我不推荐此解决方案,因为在这种情况下它通常不会等待。

The following screenshot shows rough percentile bands on how long it truly takes (from buckets of 20 samples each - dark green are the median values), with a (nominal) minimum duration between frames set at 30fps (33.333ms):以下屏幕截图显示了实际需要多长时间的粗略百分比带(每个桶有 20 个样本 - 深绿色是中值),帧之间的(标称)最小持续时间设置为 30fps(33.333ms):

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM