我经常编写使用一个框架的软件,该框架中每秒调用多次回调方法,但是在该回调内部,我只想每N
秒执行一些操作。因此,我经常这样做:
int lastMethodCallTime = 0;
int methodRunIntervalMs = 5000;
void methodThatGetsCalledManyTimesPerSecond(){
int currentTime = getCurrentTime();
if(currentTime - lastMethodCallTime >= methodRunIntervalMs){
lastMethodCallTime = currentTime;
myMethod();
}
}
但是可恶。这很丑陋,需要声明外部变量,而且非常容易发生错误(很多时候我忘记了lastMethodCallTime = currentTime;
,然后想知道为什么它被这么多次调用了)。而且,如果您有多个以不同间隔调用的方法,那么此丑陋只会成倍增加。
当然还有更优雅的方法吗?我正在寻找一种可以用任何语言实现的想法。同样,在很多情况下,也不可以将方法调用放入单独的线程中,因此我需要在这些约束内进行工作。
这个答案不是很笼统。我在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
并将其结果返回给框架,则您的类必须是通用的。这又是一个复杂的问题,但又是一个麻烦:它大部分都隐藏在漂亮的界面后面。是的,该接口是通用的,但是很好,尤其是使用该接口的代码看起来很不错。并发症隐藏在后面。