我想知道如何在快速取消响应和性能之间达成妥协,我的线程看起来类似于这个循环:
for(int i=0; i<HUGE_NUMBER; ++i) {
//some easy computation like adding numbers
//which are result of previous iteration of this loop
}
如果循环体中的计算非常简单,那么在每次迭代中添加简单的检查反应:
if (Thread.currentThread().isInterrupted()) {
throw new InterruptedException("Cancelled");
}
可能减慢代码的执行。
即使我将上述条件更改为:
if (i % 100 && Thread.currentThread().isInterrupted()) {
throw new InterruptedException("Cancelled");
}
然后,编译器不能只预先计算i
的值并仅在某些特定情况下检查条件,因为HUGE_NUMBER
是可变的并且可以具有不同的值。
所以我想询问是否有任何智能方式将此类检查添加到显示的代码中,并知道:
HUGE_NUMBER
是可变的,可以有不同的值我想说的是循环的一次迭代非常快,但迭代的HUGE_NUMBER
可能会花费更多的时间,这就是我想要避免的。
答案 0 :(得分:2)
首先,在这种情况下使用Thread.interrupted()
代替Thread.currentThread().isInterrupted()
。
你应该考虑一下检查中断标志是否真的会减慢你的计算速度!一方面,如果循环体非常简单,即使是大量的迭代(上限为Integer.MAX_VALUE)也会在几秒钟内运行。即使检查中断标志会导致20%或30%的开销,这也不会对算法的总运行时间产生太大影响。
另一方面,如果循环体不那么简单,那么它会运行得更长,测试中断标志不会是一个非常显着的开销。
不要像if (i % 10000 == 0)
这样的技巧,因为这会比“短”Thread.interrupted()
更慢地减慢计算速度。
您可以使用一个小技巧 - 但请三思,因为它会使您的代码更复杂,更不易读取:
每当你有这样的循环时:
for (int i = 0; i < max; i++) {
// loop-body using i
}
您可以将i
的总范围拆分为多个大小INTERVAL_SIZE
的间隔:
int start = 0;
while (start < max) {
final int next = Math.min(start + INTERVAL_SIZE, max);
for(int i = start; i < next; i++) {
// loop-body using i
}
start = next;
}
现在您可以在内循环之前或之后添加中断检查!
我使用以下loop-body
对我的系统(JDK 7)进行了一些测试if (i % 2 == 0) x++;
和Integer.MAX_VALUE / 2
次迭代。结果如下(预热后):
因此,即使循环体如上所述,每次迭代检查的开销仅为14%!所以建议不要做任何技巧,但只需在每次迭代中通过Thread.interrupted()
检查中断标志!
答案 1 :(得分:1)
将您的计算设为Iterator
。
虽然这听起来不是非常有用,但是这里的好处是你可以很容易地编写过滤器迭代器,它可以非常灵活。它们可以简单地添加和删除 - 如果您愿意,甚至可以进行配置。有很多好处 - 试试吧。
然后,您可以添加一个过滤Iterator
来监视时间并定期检查中断 - 或者更灵活的事情。
您甚至可以通过在脆弱的状态检查中穿插来添加进一步的过滤,而不会影响原始计算。