一种在常规调用的函数中以一定间隔重复执行的优雅方式

问题描述 投票:0回答:1

我经常编写使用一个框架的软件,该框架中每秒调用多次回调方法,但是在该回调内部,我只想每N秒执行一些操作。因此,我经常这样做:

int lastMethodCallTime = 0;
int methodRunIntervalMs = 5000;
void methodThatGetsCalledManyTimesPerSecond(){
   int currentTime = getCurrentTime();
   if(currentTime - lastMethodCallTime >= methodRunIntervalMs){
      lastMethodCallTime = currentTime;
      myMethod();
   }
}

但是可恶。这很丑陋,需要声明外部变量,而且非常容易发生错误(很多时候我忘记了lastMethodCallTime = currentTime;,然后想知道为什么它被这么多次调用了)。而且,如果您有多个以不同间隔调用的方法,那么此丑陋只会成倍增加。

当然还有更优雅的方法吗?我正在寻找一种可以用任何语言实现的想法。同样,在很多情况下,也不可以将方法调用放入单独的线程中,因此我需要在这些约束内进行工作。

loops time language-agnostic intervals
1个回答
0
投票

这个答案不是很笼统。我在Java中提供了一个建议,您可能会看到是否可以将其适应于所使用的其他语言。我正在使用一些Java功能。

此外,我无法编写比您已经完成的代码更精美的代码。我的建议是应用Bjarne Stroustrup编写的内容:只要您可以将代码隐藏在漂亮的界面后面,代码就可以很丑陋。这将使您可以像这样编写示例代码:

CallFrequencyController myCallFrequencyController
        = new CallFrequencyController(5, TimeUnit.SECONDS, this::myMethod);

void methodThatGetsCalledManyTimesPerSecond() {
    myCallFrequencyController.call();
}

这是我隐藏丑陋代码的地方:

class CallFrequencyController {

    Instant nextCallTime = Instant.now();
    final long methodRunIntervalNanos;
    final Runnable methodToCall;

    public CallFrequencyController(int frequency, TimeUnit frequencyUnit, Runnable methodToCall) {
        methodRunIntervalNanos = frequencyUnit.toNanos(frequency);
        this.methodToCall = methodToCall;
    }

    public void call() {
        Instant now = Instant.now();
        if (now.isBefore(nextCallTime)) {
            return;
        }

        methodToCall.run();

        nextCallTime = now.plusNanos(methodRunIntervalNanos);
    }

}

您可以开发一次该类并进行全面测试,然后您不必担心忘记更新上一个或下一个通话时间或编写其他错误。

如果需要将参数传递给myMethod并将其结果返回给框架,则您的类必须是通用的。这又是一个复杂的问题,但又是一个麻烦:它大部分都隐藏在漂亮的界面后面。是的,该接口是通用的,但是很好,尤其是使用该接口的代码看起来很不错。并发症隐藏在后面。

© www.soinside.com 2019 - 2024. All rights reserved.