1

我目前遇到了计时器问题。

我有一个每隔 x 秒由计时器启动的功能。现在,在不同的条件下,函数执行有时会花费更长的时间。所以我希望计时器仅在完成功能后重新运行。我怎样才能做到这一点?

4

2 回答 2

3

在它退出之前,您的函数可能会触发一个事件。该事件将被另一个函数捕获,该函数将启动计时器。

于 2020-05-25T12:19:55.893 回答
1

我的建议是避免为此使用 Timer 类。造成这种情况的原因正是您现在处理这个问题时遇到的问题。

System.Threading.Timer 类是可重入的,这意味着如果在前一个触发器调用返回之前间隔已经过去,即使它已经在执行,它也会再次调用该方法。您需要以使代码有点混乱的方式处理方法和触发器之间的协作。

但是,让我们重新考虑一下这个问题。

你想要

  1. 在间隔上调用方法
  2. 如果方法调用的执行时间比间隔时间长,则立即再次触发

更好的方法是省去触发器并编写自己的使用任务。

这是一个非常简单的例子:

public static async Task CallPeriodicAsync(Func<CancellationToken, Task> func,
    int intervalMilliseconds, CancellationToken cancellationToken)
{
    while (true)
    {
        var delay = Task.Delay(intervalMilliseconds, cancellationToken);
        await func(cancellationToken);
        await delay;
    }
}

你会这样开始:

CancellationToken cancellationToken = ...;
CallPeriodicAsync(async ct =>
{
    int timeToRun = 1000 + r.Next(14000);
    Console.WriteLine($"This time running for {timeToRun} ms");
    await Task.Delay(timeToRun, ct);
}, 10000, cancellationToken);

示例输出将是(我在 CallPeriod 方法中也有一些 Console.WriteLine 来说明它是否会在此运行中等待或立即触发):

This time running for 12162 ms
trigger again immediately
This time running for 14706 ms
trigger again immediately
This time running for 12756 ms
trigger again immediately
This time running for 2187 ms
delay until next is 7813 ms
This time running for 5221 ms
delay until next is 4767 ms
This time running for 8866 ms

基本上这个 CallPeriod 方法将调用你的方法并给它 X 毫秒来完成。如果它完成得更快,它将为其余部分增加延迟,如果它完成得较慢,它将重新开始循环。

这意味着我关于“保持原始间隔”的问题仍然相关。

例如,保持原始间隔会导致这种触发(---*只是时间线),每 4 秒:

v               v               v               v               v
*---*---*---*---*---*---*---*---*---*---*---*---*---*---*---*---*---*
[...]           [..................][.......]   [...]           [....

而我上面的解决方案会在延迟后扭曲周期:

v               v               v                   v               v
*---*---*---*---*---*---*---*---*---*---*---*---*---*---*---*---*---*
[...]           [..................][.......]       [...]           [....
                                v                   ^
                                +-- because we got -+
                                 one second delayed
                                 here we're now one
                                 second late always
于 2020-05-25T12:23:21.783 回答