1

我想在java中使用反射或内省来替换“IF - ELSE”语句,我想知道“反射”VS“IF - ELSE”语句有多昂贵?如果我使用大约 700.000 次迭代的循环,哪个更有效?

4

3 回答 3

1

参见 Effective Java,第 53 条:首选接口而不是反射

性能受到影响。反射方法调用比普通方法调用慢得多。到底慢了多少很难说,因为有很多因素在起作用。在我的机器上,速度差异可以小到两倍或大到 50 倍。

于 2013-10-10T14:32:45.487 回答
0

您可能知道,条件的问题在于它们削弱了处理器的可预测性功能。这意味着如果预取是错误的,它实际上会变成一个劣势。这就是当今处理器在不知道比较结果可能是什么时发生的情况,因此他们打赌。在 IF-ELSE 语句中,处理器有 50% 的概率正确预测要执行的下一条指令。如果幸运的话,我们每个周期执行更多指令,否则,我们会得到大约 16 个周期的中等惩罚,以便处理器从错误的预取中恢复。

也就是说,让我们继续反思。反思是卑鄙的,中频表现对你很重要。在大多数框架中,反射与地址调用是C_reflection = 3*C_address_call. 在 Java 中情况更糟,我并没有关于它的官方数据。最大的问题是名称/地址/可用性解析。

也就是说,让我们去现实世界看看一些数字。正如我们现在可以理解、证明甚至预测结果一样。

我们测试 2 个类,3 个测试。总共 1000 万次调用/测试 | 每堂课 500 万次调用:

  1. 有条件的
  2. 反射
  3. 通用接口

这些是以秒为单位的数字:

条件 - 0.022333

反射 - 3.02087

接口 - 0.012547

因此,在您的情况下,通用接口是赢家,其次是执行时间几乎翻倍的条件调用(出于上述原因)。最后一个非常显着的区别是反射。

这是测试的代码 * :

import java.lang.reflect.InvocationTargetException;

public class JavaReflectionTest {

    public interface ClassInterface {
        public void execute();
        public String getCount();
    }


    public static class ClassOne implements ClassInterface {

        int count = 0;

        public String getCount(){
            return String.valueOf(count);
        }

        public void execute(){
            count++;
        }
    }

    public static class ClassTwo implements ClassInterface {

        int count = 0;

        public String getCount(){
            return String.valueOf(count);
        }

        public void execute(){
            count++;
        }
    }


    public static void main(String[] args) throws SecurityException, NoSuchMethodException, 
                                                    IllegalArgumentException, IllegalAccessException, 
                                                    InvocationTargetException, ClassNotFoundException, InterruptedException {

        ClassOne one = new ClassOne();
        ClassTwo two = new ClassTwo();
        ClassInterface ione = new ClassOne();
        ClassInterface itwo = new ClassTwo();
        long stopT;
        long startT;
        int i;
        int mod;

        //Warm up
        for(i=0;i<350000;i++){
            one.execute();
            two.execute();
            ione.execute();
            itwo.execute();
            one.getClass().getMethod("execute").invoke(one,null);
            two.getClass().getMethod("execute").invoke(two,null);
        }

        //Test conditional call
        one = new ClassOne();
        two = new ClassTwo();
        Thread.sleep(1000);
        startT=System.nanoTime();
        for(i=0;i<10000000;i++){
            mod=i%2;
            if(mod==0)
                one.execute();
            else
                two.execute();
        }
        stopT=System.nanoTime();
        System.out.println("Conditions - " + ((stopT-startT)/1000000000.0f)+ " Calls 1: " + one.getCount() + " Calls 2: " + two.getCount());

        //Test reflection
        one = new ClassOne();
        two = new ClassTwo();
        Thread.sleep(1000);
        startT = System.nanoTime();
        for(i=0;i<5000000;i++){
            mod=i%2;
            one.getClass().getMethod("execute").invoke(one,null);
            two.getClass().getMethod("execute").invoke(two,null);
            mod=i%2;
        }
        stopT=System.nanoTime();
        System.out.println("Reflection - " + ((stopT-startT)/1000000000.0f)+ " Calls 1: " + one.getCount() + " Calls 2: " + two.getCount());

        //Test common interface
        ione = new ClassOne();
        itwo = new ClassTwo();
        Thread.sleep(1000);
        startT = System.nanoTime();
        for(i=0;i<5000000;i++){
            mod=i%2;
            ione.execute();
            itwo.execute();
            mod=i%2;
        }
        stopT=System.nanoTime();
        System.out.println("Interface - " + ((stopT-startT)/1000000000.0f) + " Calls 1: " + ione.getCount() + " Calls 2: " + itwo.getCount());

    }
}
  • 在创建性能测试之前,我们需要确保编译器将尽可能少地优化/修改我们的代码,这解释了测试中的一些您可能不直观的语句。
于 2013-10-10T16:36:39.613 回答
0

我找到了这个 文档,我了解风险

于 2013-10-10T15:25:58.463 回答