有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java中变量参数方法的性能

我有一个关于Java中参数数量可变的方法性能的问题

假设我有以下两种选择:

public static final boolean isIn(int i, int v1, int v2) {
    return (v1 == i) || (v2 == i);
}

public static final boolean isIn(int i, int... values) {
    for (int v : values) {
        if (i == v) {
            return true;
        }
    }
    return false;
}

现在主要的问题来了,当我有第一个方法的版本时,它的参数会增加到20、30甚至50个。现在这只会伤害眼睛。好的,这是遗留代码,我想用一个变量arguments方法替换所有代码

你知道这会对绩效产生什么影响吗?编译器是否有可能对第二种方法进行一些优化,使其或多或少类似于第一种形式

编辑:好的,也许我不够清楚。我没有50个参数的方法的性能问题。正如Peter Lawrey所说,这只是关于可读性。 我想知道,如果我切换到具有可变参数数的新方法,是否会出现性能问题
换句话说:如果您关心性能,那么最好的方法是什么?方法有50个参数,还是只有一个方法有变量参数


共 (6) 个答案

  1. # 1 楼答案

    编译器几乎不进行优化。JVM可以优化代码,但这两种方法的性能并不相同。如果您有像isIn(i, 1,2,3,4,5,6,7,8,9 /* plus 40 more */)这样的代码行,那么IMHO需要担心的不仅仅是性能问题。我首先会担心可读性

    如果您担心性能问题,请将参数作为int[]传递,以便重用

    顺便说一句,查找大型int值集的最有效方法是使用类似于TIntHashSet的集合

  2. # 2 楼答案

    我问了同样的问题,然后转向实验

    public class ArgTest {
    
      int summation(int a, int b, int c, int d, int e, int f) {
        return a + b + c + d + e + f;
      }
    
      int summationVArgs(int... args) {
        int sum = 0;
        for (int arg : args) {
          sum += arg;
        }
        return sum;
      }
    
      final static public int META_ITERATIONS = 200;
      final static public int ITERATIONS = 1000000;
    
      static public void main(String[] args) {
        final ArgTest at = new ArgTest();
        for (int loop = 0; loop < META_ITERATIONS; loop++) {
          int sum = 0;
          final long fixedStart = System.currentTimeMillis();
          for (int i = 0; i < ITERATIONS; i++) {
            sum += at.summation(2312, 45569, -9816, 19122, 4991, 901776);
          }
          final long fixedEnd = System.currentTimeMillis();
          final long vargStart = fixedEnd;
          for (int i = 0; i < ITERATIONS; i++) {
            sum += at.summationVArgs(2312, 45569, -9816, 19122, 4991, 901776);
          }
          final long vargEnd = System.currentTimeMillis();
          System.out.printf("%03d:%d Fixed-Args: %d ms\n", loop+1, ITERATIONS, fixedEnd - fixedStart);
          System.out.printf("%03d:%d Vargs-Args: %d ms\n", loop+1, ITERATIONS, vargEnd - vargStart);
        }
        System.exit(0);
      }
    
    }
    

    如果在现代JVM(这里是1.8.020)上运行此代码,您将看到可变数量的参数会导致性能开销和内存消耗

    我只发布前25次跑步记录:

    001:1000000 Fixed-Args: 16 ms
    001:1000000 Vargs-Args: 45 ms
    002:1000000 Fixed-Args: 13 ms
    002:1000000 Vargs-Args: 32 ms
    003:1000000 Fixed-Args: 0 ms
    003:1000000 Vargs-Args: 27 ms
    004:1000000 Fixed-Args: 0 ms
    004:1000000 Vargs-Args: 22 ms
    005:1000000 Fixed-Args: 0 ms
    005:1000000 Vargs-Args: 38 ms
    006:1000000 Fixed-Args: 0 ms
    006:1000000 Vargs-Args: 11 ms
    007:1000000 Fixed-Args: 0 ms
    007:1000000 Vargs-Args: 17 ms
    008:1000000 Fixed-Args: 0 ms
    008:1000000 Vargs-Args: 40 ms
    009:1000000 Fixed-Args: 0 ms
    009:1000000 Vargs-Args: 89 ms
    010:1000000 Fixed-Args: 0 ms
    010:1000000 Vargs-Args: 21 ms
    011:1000000 Fixed-Args: 0 ms
    011:1000000 Vargs-Args: 16 ms
    012:1000000 Fixed-Args: 0 ms
    012:1000000 Vargs-Args: 26 ms
    013:1000000 Fixed-Args: 0 ms
    013:1000000 Vargs-Args: 7 ms
    014:1000000 Fixed-Args: 0 ms
    014:1000000 Vargs-Args: 7 ms
    015:1000000 Fixed-Args: 0 ms
    015:1000000 Vargs-Args: 6 ms
    016:1000000 Fixed-Args: 0 ms
    016:1000000 Vargs-Args: 141 ms
    017:1000000 Fixed-Args: 0 ms
    017:1000000 Vargs-Args: 139 ms
    018:1000000 Fixed-Args: 0 ms
    018:1000000 Vargs-Args: 106 ms
    019:1000000 Fixed-Args: 0 ms
    019:1000000 Vargs-Args: 70 ms
    020:1000000 Fixed-Args: 0 ms
    020:1000000 Vargs-Args: 6 ms
    021:1000000 Fixed-Args: 0 ms
    021:1000000 Vargs-Args: 5 ms
    022:1000000 Fixed-Args: 0 ms
    022:1000000 Vargs-Args: 6 ms
    023:1000000 Fixed-Args: 0 ms
    023:1000000 Vargs-Args: 12 ms
    024:1000000 Fixed-Args: 0 ms
    024:1000000 Vargs-Args: 37 ms
    025:1000000 Fixed-Args: 0 ms
    025:1000000 Vargs-Args: 12 ms
    ...
    

    即使在最好的时候,Vargs Args也从未下降到0毫秒

  3. # 3 楼答案

    这将与您声明的相同

     isIn(int i, int[] values) {
    

    但是,在调用方法时,在打包变量时会有一些小的开销

  4. # 4 楼答案

    致@Canonical Chris

    我不认为你们测试中的问题来自可变参数。由于for loop,函数sumationVArgs需要更多的时间来完成

    我创建了这个函数并添加到基准测试中

    int summationVArgs2(int... args) {
            return args[0] + args[1] + args[2] + args[3] + args[4] + args[5];
        }
    

    这就是我所看到的:

    028:1000000 Fixed-Args: 0 ms
    028:1000000 Vargs-Args: 12 ms
    028:1000000 Vargs2-Args2: 0 ms
    

    函数“summationVArgs”中的for loop被编译成比add函数更多的操作。它包含add operation以增加迭代器、check operation以检查条件和branch operation以循环和退出循环,并且除了分支操作以退出循环外,所有这些操作都对每个循环执行一次

    对不起,我的英语不好。我希望你能理解我的英语:)

  5. # 5 楼答案

    听说过两条优化规则:

    • 不要优化
    • (仅限专家!)还没有优化

    换言之,从性能的角度来看,您不应该关心这一点

  6. # 6 楼答案

    当您的分析器输出显示这是一个问题时,请返回。在那之前,这是过早的优化