显示 for 循环进度,而不会严重影响 Java 中的性能



假设我有一个这样的 for 循环(忽略可怕的效率,这只是一个例子):

ArrayList<Integer> primes = new ArrayList<>();
for(int i = 0; i < 10000; i++){
  if(isPrime(i)){
    primes.add(i);
  }
}

我想每隔 10% 显示循环的进度,但我不知道如何在不影响性能的情况下做到这一点。这是我到目前为止能想到的:

ArrayList<Integer> primes = new ArrayList<>();
int n = 10000/10;
for(int i = 0; i < 10000; i++){
  if(isPrime(i)){
    primes.add(i);
  }
  if(i == n){
    System.out.println(String.valueOf(i).charAt(0)+"0% Complete");
    n+=10000/10;
  }
}

有没有更有效的方法呢?

我发现在打印进度时对步长值(例如 10% 增量)进行硬编码并不是那么有用。最好每 X(毫秒)打印/更新一次进度,这样您就可以始终看到实际进度。

如果您的逻辑足够慢,需要进度,则打印进度对性能的影响微乎其微,并且看到良好的进度值会使其感觉更快。

因此,要按时间间隔更新进度,请执行以下操作:

final long count = 1_000_000_000L;
long nextTime = 0;
for (long i = 0; i < count; i++) {
    long time = System.currentTimeMillis();
    if (time >= nextTime) {
        System.out.printf("%.2f%%r", i * 100d / count);
        nextTime = time + 200;
    }
    // slowMethod();
}
System.out.println("100.00%");

由于我没有"slowMethod",我只是增加了迭代次数,使其足够慢以查看进度。

200值意味着它将每 200 毫秒打印一次进度,即每秒 5 次。如果你认为这太多了,你可以增加价值,但我喜欢它。

使用 r 打印进度意味着在一行上更新进度。如果从 Windows 命令提示符运行,则工作正常,但 IDE(例如 Eclipse)可能只是将其视为换行符,在控制台窗格中的新行上打印每个进度更新,在这种情况下,频繁更新不太可取。

我是这种方法的粉丝:

ArrayList<Integer> primes = new ArrayList<>();
final int I_MAX = 10_000; final int N_MAX = I_MAX / 10;
for (int i = 0, n = 10; i < I_MAX; i++, n++, n %= N_MAX) {
    if (i.isPrime()) primes.add(i);
    if (n == 0) System.out.println((i / (I_MAX / 10)) + "0% complete");
}

你也可以做这样的事情,这不涉及跟踪另一个变量:

ArrayList<Integer> primes = new ArrayList<>();
final int I_MAX = 10_000;
for (int i = 0; i < I_MAX; i++) {
    if (i.isPrime()) primes.add(i);
    if (i % (I_MAX / 10) == 0) System.out.println((i / (I_MAX / 10)) + "0% complete");
}
ArrayList<Integer> primes = new ArrayList<>();
int n = 10000/10;
for(int i = 0; i < 10000; i++){
  if(i.isPrime()){
    primes.add(i);
  }
  if((i+1) % n == 0){
    System.out.println((i+1)/n*10 + "% Complete");
  }
}

虽然这不会以 0% 打印,但我认为类似的概念可以完成这项工作。

性能绝对不会受到太大影响,因为您只在每次迭代中添加一个恒定的时间因子。

使用嵌套的 for 循环。您会注意到,此答案每次迭代只有一个比较,而不是两个。

ArrayList<Integer> primes = new ArrayList<>();
System.out.println("0% Complete");
for(int i = 0; i < 10; i++){
  for(int j=0; j<1000;j++){
    if(i.isPrime()){
      primes.add(i);
    }
  }
  System.out.println(i+"0% Complete");
}
System.out.println("100% Complete");

最新更新