C#定时环路速率不准确

C#定时环路速率不准确,c#,.net,timing,C#,.net,Timing,我试图在C#中创建一个方法,通过该方法,我可以以目标速率重复执行操作(在我的特定应用程序中,它正在发送UDP数据包)。我知道C#中的计时器不准确会阻止输出精确到目标速率,但尽最大努力就足够了。然而,在更高的利率下,时机似乎完全错了 while (!token.IsCancellationRequested) { stopwatch.Restart(); Thread.Sleep(5); // Simulate process int processTime = (in

我试图在C#中创建一个方法,通过该方法,我可以以目标速率重复执行操作(在我的特定应用程序中,它正在发送UDP数据包)。我知道C#中的计时器不准确会阻止输出精确到目标速率,但尽最大努力就足够了。然而,在更高的利率下,时机似乎完全错了

while (!token.IsCancellationRequested)
{
    stopwatch.Restart();

    Thread.Sleep(5); // Simulate process

    int processTime = (int)stopwatch.ElapsedMilliseconds;
    int waitTime = taskInterval - processTime;

    Task.Delay(Math.Max(0, waitTime)).Wait();
}
有关控制台应用程序的完整示例,请参阅

运行时,该测试应用程序的FPS输出显示约44-46 Hz,目标为60 Hz。然而,在较低的速率(比如20赫兹)下,输出速率更接近目标。我不明白为什么会这样。我的代码有什么问题?

如果替换此代码:

Task.Delay(Math.Max(0, waitTime)).Wait();
为此:

Thread.Sleep(Math.Max(0, waitTime));

您应该以更高的速率获得更接近的值(为什么要使用
Task.Delay(..).Wait()
)。

问题是
Thread.Sleep
(或
Task.Delay
)不是很准确。看看这个:

解决这个问题的一种方法是启动计时器一次,然后进行一个循环,每次迭代延迟约15毫秒。在每次迭代中,计算到目前为止应该执行操作的次数,并将其与到目前为止运行操作的次数进行比较。然后运行操作足够多的时间以赶上进度

以下是一些代码示例:

private static void timerTask(CancellationToken token)
{
    const int taskRateHz = 60;

    var stopwatch = new Stopwatch();

    stopwatch.Start();

    int ran_so_far = 0;

    while (!token.IsCancellationRequested)
    {
        Thread.Sleep(15);

        int should_have_run =
            stopwatch.ElapsedMilliseconds * taskRateHz / 1000;

        int need_to_run_now = should_have_run - ran_so_far;

        if(need_to_run_now > 0)
        {
             for(int i = 0; i < need_to_run_now; i++)
             {
                 ExecuteTheOperationHere();
             }

             ran_so_far += need_to_run_now;
        }
    }
}
private static void timerTask(CancellationToken令牌)
{
常数int taskRateHz=60;
var stopwatch=新秒表();
秒表。开始();
int-ran\u-so\u-far=0;
而(!token.IsCancellationRequested)
{
睡眠(15);
int应该运行=
秒表。延时百万秒*任务速率Hz/1000;
int need_to_run_now=应该_run-run_至今;
如果(需要立即运行>0)
{
for(int i=0;i<现在需要运行;i++)
{
在此处执行操作();
}
跑了这么远+=现在需要跑;
}
}
}

请注意,如果进程要在很长一段时间内保持活动状态,您希望使用
long
s而不是
int
s。

是否得到负
waitTime
值?如果是这种情况,那么你无法每秒处理足够的请求。顺便说一下,请在问题it self中发布代码示例。试着举一个最小的例子。不,当以60 Hz的目标速率运行时,我的等待时间值为10-11 ms。这是可以证明问题的最简单的例子。看看这个:计时器分辨率也在50-60 Hz范围内。请务必在问题本身中包含一个最小的示例,现在可以结束。谢谢,这确实纠正了性能。我的库针对的是.Net平台标准,但线程太多。睡眠对我来说不可用。@Henkholtman我也很感兴趣,为什么,到目前为止还没有找到结论性的答案。但它确实“修复”了问题中提到的问题(不是真的,因为正如你在评论中提到的,无论如何这不是应该怎么做的)。@HenkHolterman,这应该没问题,因为代码会检测到它需要多次运行操作,并立即运行它们以赶上进度。这意味着执行时间不是以完美的方式均匀分布的,但它可以保证平均60个操作以合理的精度在一秒钟内运行。