【问题标题】:Performance many If-statements vs long logical Expression [duplicate]执行许多 If 语句与长逻辑表达式 [重复]
【发布时间】:2014-06-26 21:26:30
【问题描述】:

如果我有一个长逻辑表达式,将其拆分为多个 if 语句或使用长逻辑表达式是否重要?

例子:

if((A||B)&&(B||C)&&(C||D)&&.....(N||N+1))
      System.out.println("Hello World");

或者这样更快

 if(A||B)
  if(B||C)
   if(C||D)
    ...
     if(N||N+1)
      System.out.println("Hello World");

我认为长表达式更快,但许多 if 可以更好地阅读。 但我不确定许多 if 语句是否可行?

【问题讨论】:

  • 主要是口味问题。使用更容易理解的内容。
  • 更容易阅读的代码肯定运行得更快
  • 许多 if 不能更快。除非编译器优化 if 使它们相同,否则长逻辑表达式应该更快。
  • 为了更好地阅读长逻辑表达式,您可以在每个 && 之后将其格式化为多行,这样它看起来就像多行 ifs
  • 如果它做同样的事情,我希望性能是一样的。

标签: java if-statement logical-operators


【解决方案1】:

编辑:这是错误的,请在下面查看我的编辑

在我的测试用例中,嵌套 if 更快。我不知道为什么。我的预期正好相反。也许我测试错了。

测试用例

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

public class Test {
    private static final int RUN_TIMES = 100000000;
    private static final int HEATUP_TIMES = 100000;
    private static final int RESET_EVERY = 1000;

    public static void main(String[] args) {
        Test instance = new Test();
        instance.doTest();
    }

    private long a;
    private long b;
    private long c;
    private long d;
    private long e;
    private long f;
    private AtomicLong n;

    private void doTest() {
        Runnable t1 = new Runnable() {
            public void run() {
                if (
                        (a > b || a > c)
                        && (a > d || b > d) 
                        && (c > e || e > f)
                        && (f > a || f > b) 
                        && (f > e || f > a)
                        && (a > f || f > d) 
                        && (d > e || e > d)
                        && (f > e || f > a) 
                        && (f > b || f > a)) {
                    n.incrementAndGet();
                }
            }

            public String toString() {
                return "task1";
            }
        };
        Runnable t2 = new Runnable() {
            public void run() {
                if (a > b || a > c)
                    if (a > d || b > d)
                        if (c > e || e > f)
                            if (f > a || f > b)
                                if ((f > e || f > a))
                                    if ((a > f || f > d))
                                        if ((d > e || e > d))
                                            if ((f > e || f > a))
                                                n.incrementAndGet();
            }
            public String toString() {
                return "task2";
            }
        };

        List<Runnable> tasks = Arrays.asList(t1, t2, t1, t2, t1, t2, t1, t2, t1, t2);
        for (Runnable r: tasks) {
            benchmark(r);
        }
    }

    private void reset() {
        java.util.Random rnd = new java.util.Random();
        this.a = rnd.nextLong();
        this.b = rnd.nextLong();
        this.c = rnd.nextLong();
        this.d = rnd.nextLong();
        this.e = rnd.nextLong();
        this.f = rnd.nextLong();
    }

    private void benchmark(Runnable t) {
        n = new AtomicLong();
        reset();
        for (int i = 0; i < HEATUP_TIMES; i++) {
            t.run();
        }
        long t0 = System.nanoTime();
        int r = 0;
        for (int i = 0; i < RUN_TIMES; i++) {
            if (r == 0) {
                reset();
                r = RESET_EVERY + 1;
            }
            r--;
            t.run();
        }
        long t1 = System.nanoTime();
        System.out.println(String.format("Task %s was run %d times in %.3f ms",
                t, RUN_TIMES, (t1 - t0) / 1000000d));
        System.out.println("n = " + n);
    }
}

结果

Task task1 was run 100000000 times in 753,292 ms
n = 12666654
Task task2 was run 100000000 times in 491,695 ms
n = 12359347
Task task1 was run 100000000 times in 663,144 ms
n = 12530518
Task task2 was run 100000000 times in 499,428 ms
n = 12567555
Task task1 was run 100000000 times in 740,334 ms
n = 12504492
Task task2 was run 100000000 times in 424,854 ms
n = 12379367
Task task1 was run 100000000 times in 721,993 ms
n = 12541529
Task task2 was run 100000000 times in 430,007 ms
n = 12647635
Task task1 was run 100000000 times in 719,680 ms
n = 12598586
Task task2 was run 100000000 times in 432,019 ms
n = 12581569

原子长n是为了测试我没有弄错一个条件,当条件满足时有事做。

接受后编辑

正如 TheOtherDude 指出的那样,第二个测试缺少条件。确定结果完全不同。现在两个测试都需要相同的时间。

Task task1 was run 100000000 times in 907,538 ms
n = 12401389
Task task2 was run 100000000 times in 941,928 ms
n = 12325413
Task task1 was run 100000000 times in 850,497 ms
n = 12417405
Task task2 was run 100000000 times in 873,328 ms
n = 12571559
Task task1 was run 100000000 times in 840,028 ms
n = 12538526
Task task2 was run 100000000 times in 865,157 ms
n = 12461449
Task task1 was run 100000000 times in 860,125 ms
n = 12252240
Task task2 was run 100000000 times in 862,829 ms
n = 12350338
Task task1 was run 100000000 times in 866,317 ms
n = 12597585
Task task2 was run 100000000 times in 866,483 ms
n = 12538526

【讨论】:

  • 我的运行时是 JDK 1.7.0_51
  • 做了类似的测试同样的结果
【解决方案2】:

好的,这个问题很老了,但我认为仍然值得回答。

任务 2 缺少一个条件,任务 1 正在执行。它是最后一个:

&& (f > b || f > a)) {

这可能有助于任务 2 的速度优势。您应该纠正它并再次测量。

如果看到 OldCurmudgeon 给出的第三个选项的速度会很有趣。

另一件事。您会看到执行时间的随机分布。明智的做法是检查执行时间的差异是否具有统计意义。

另一半

【讨论】:

  • 你是对的!缺失条件是造成差异的原因。现在我的两个测试都需要同样的时间。我将删除我的答案,我认为@Jaran 应该接受你的答案。好吧,只要被接受,我就不能删除它。
【解决方案3】:

您应该永远在有可衡量且显着的好处时牺牲简单性来换取运行时性能。显然这里没有可衡量的好处,否则您就不会问这个问题。

当所有其他方法都失败时 - 尝试 simple

您的选择都不简单 - 尝试其他方法。

public boolean goodToGo(boolean... flags) {
    boolean good = true;
    for ( int i = 0; i < flags.length - 1 && good; i++ ) {
        good &= flags[i] || flags[i+1];
    }
    return good;
}

public void test() {
    if ( goodToGo(true, true, false, true, false, false)) {
        System.out.println("Hello");
    }
}

【讨论】:

  • 旁观者眼中的简洁 ;-)
猜你喜欢
  • 2014-11-22
  • 2021-10-16
  • 1970-01-01
  • 1970-01-01
  • 2016-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多