原文出处

早两天写了《从把三千行代码重构成15行代码谈起》这篇文章,看到评论中有一些同学的回复还是在质疑反射的性能,好像程序用上了反射,就像开上了拖拉机似的。本来我觉得这个话题没有什么好讨论的了,网上已经有太多太多的文章在说这个问题,有疑问的大可以到网上找相关的文章来查阅。但是,我想起来我刚编程的时候,也是遇到这种困惑到网上一查找,从各种角度阐述的都有,本质基本都说出来了,但是还是有很多人不理解,我这里就从我的角度再说一遍。

反射肯定比直接调用慢

这个毋庸置疑了,我这篇文章也不是证明反射有多高效的。

现在的快递哥很火,那我们就举个快递的例子。如果快递员就在你住的小区,那么你报一个地址:xx栋xx号,那么快递员就可以马上知道你在哪里,直接就去到你家门口;但是,如果快递员是第一次来你们这里,他是不是首先得查查百度地图,看看怎么开车过去,然后到了小区是不是得先问问物管xx栋怎么找,然后,有可能转在楼下转了两个圈才到了你的门前。

我们看上面这个场景,如果快递员不熟悉你的小区,是不是会慢点,他的时间主要花费在了查找百度地图,询问物业管理。OK,反射也是一样,因为我事先什么都不知道,所以我得花时间查询一些其他资料,然后我才能找到你。大家有兴趣可以查看反射的实现原理,以及MetaData的相关概念。

反射到底比直接调用慢多少?

好了,我们知道反射肯定慢的,那么是不是反射就不能用了呢?有些人一听到慢,就非常着急的下结论,反射怎样怎样不行,怎样怎样不能用。但是,同学,反射到底比直接调用慢多少,你造吗,能给我个实际的数据吗?很多人其实对性能只有个模糊的概念,而没有数值支撑。之前我给同事找了一个动态解析表达式的类库,他觉得不太好用,他很聪明,很快的找到了用DataTale.Compute可以实现公式的动态解析。我问他,这个方法和我给的类库性能上有什么区别?他跟我说,这个已经很快了,执行1秒都不到。我一听,就觉得不对劲,你的思想还停留在秒级,跟我谈什么性能?

怎么去判断一个函数的性能?因为函数的执行太快太快了,你需要一个放慢镜,这样才能捕捉到他的速度。怎么做?把一个函数执行一百万遍或者一千万遍,你才能真正了解一个函数的性能。也就是,你如果想判断性能,你就不能还停留在秒级,毫秒级的概念,你必须用另外一个概念替代,才能知道真正的性能。结果我同事把这两种方法执行了100w遍,确实,我提供的类库比他的快了8秒。

好了,现在拿我早两天提供的工厂方法来做测试,其中CodeTimer的实现参考赵大神的文章《一个简单的性能计数器:CodeTimer》:

测试方法如下:

 代码如下
1 [Test]
public void TestReflector()
{
    CodeTimer.Time("Direct", 100 * 10000,
        () =>
        {
            var instance = new ConnectionTest();
        });

CodeTimer.Time("Reflect", 100 * 10000,
        () =>
        {
            this.GetType().Assembly.CreateInstance("TestPropertyGrid.ConnectionTest");
        });
}

测试结果如下:

Direct
    Time Elapsed:    25ms
    CPU Cycles:    57,582,163
    Gen 0:         14
    Gen 1:         0

Reflect
    Time Elapsed:    3,231ms
    CPU Cycles:    8,001,720,795
    Gen 0:         269
    Gen 1:         1

看到没,我们的放大镜起作用了,现在我们大概可以下这么一个结论:在执行100万遍的时候,反射大概把直接调用慢50~100倍。100倍,咋一看,是相差很大的,但是,我前文说了,别着急下结论,你要看看前提条件。自古我们就喜欢断章取义,比如“以德报怨”这个成语,好像古人说让我们遇到不好的,你不能怨恨,要更好的对待他人,别人打你左脸一巴掌,你应该把右脸伸过去让他再打一下。但实际这个成语是怎样的呢?

或曰:“以德报怨,何如?”
    子曰:“何以报德?以直报怨,以德报德”

老孔的意思其实是如果别人对你好,那么你就对他好,要是他招你惹你了,你就干他娘的!你看,傻眼了吧?
有多少情况下需要考虑反射带来的影响?

我认为这个情况是非常非常少的,绝大多数的我们根本就无需考虑这个。就上我上一篇文章提到的工厂,你程序有多少个实体,有100万个吗?如果你只是在弹出窗口的时候new一下,这个百万分之十秒的影响对你很重要吗?

另外,有些人讲,我要是真有这种需求,要把一个对象new一百万遍,那不还是慢吗?这种情况有没有,有!比如我有100w条记录,需要取出来,然后通过反射赋值到一个Model类中。

但是对于这种情况,如果你真是这么想的话,我只能说,你坐办公室坐久了,脑袋生锈了,该去爬爬山,泡泡妞了。如果你需要对一个对象反射一百万遍,那么你就应该缓存这个对象了。拿我们上面那个例子来说,如果这个快递员给小区的人送一百万遍的快递还认不得路,每次都还得百度地图,然后问物业管理,你丫的你还没把他开掉了,那你脑袋不是秀逗了,要不就是任性的有钱人。

上面代码如果缓存之后执行一百万遍,跟直接调用有多大的区别?我这里就不贴代码了,免得你们直接看结果没有意思,自己把代码敲一遍,印象更深刻。

那么,还有没有更快的办法,有。比如你的快递员开始用的是IPHONE4,现在可以考虑给他买个6+。在.net中,提供了Emit的相关方法来让你更快的反射。这里送你一个通过反射快速给Model赋值的轮子“Dapper”,自己回家造去。
编程中是否应该使用反射?

其实看完上面的文字,我相信你们都有了一个初步的判断,而我的看法是:绝大多数的情况下你都可以用反射。

如果你觉得是因为反射导致你程序慢的话,那么,请先用放慢镜好好观察一下,到底是不是反射的问题。如果你确定是反射的问题,那么你再好好的考虑下是不是你没有用对反射,是不是像上面那个走了一百万遍都不认识路的快递员一样。最后,如果你觉得性能上还是不够,那么我建议你升级下硬件吧,把硬件性能上升个3%总好过你请个牛逼的工程师来帮你做这种极限的优化,有一句话我觉得很对“工程师比服务器要昂贵的多”。如果你还非得跟我较劲,那么,没办法了,你程序对性能的要求已经超出了本文讨论的范畴,如果你真有这种需求了,我觉得你也没有必要看我这篇文章了,因为你已经足够牛逼到对系统语言都有深入了解了。

大多时候,我们会把程序的性能归结于编程语言,或者使用了反射等技术,而甚少去关心自己的代码,这种心态会导致你技术的发展越来越缓慢,因为你已经失去了求知的欲望,以及一颗追求技术进步的心。请你记住,更多的时候,影响我们程序性能的,是你编程的思想,你对待编码的态度!
总结

好吧,说了这么多,估计很多人直接就拖到文章末尾然后因为文章码了这么多字而默默点了个赞,那么,我在最后给大家奉献一下本文的精华:

1、反射大概比直接调用慢50~100倍,但是需要你在执行100万遍的时候才会有所感觉
2、判断一个函数的性能,你需要把这个函数执行100万遍甚至1000万遍
3、如果你只是偶尔调用一下反射,请忘记反射带来的性能影响
4、如果你需要大量调用反射,请考虑缓存。
5、你的编程的思想才是限制你程序性能的最主要的因素

JAVA反射会降低你的程序性能吗?的更多相关文章

  1. 入门级 JAVA反射机制

    1.什么是反射? Java中的反射机制是Java语言的一个很重要的特性,是Java “动态性” 的重要体现.Java反射机制让我们在程序运行状态中,对于任意一个类,都能知道这个类的所有属性和方法:对于 ...

  2. Java反射机制的浅显理解(这篇文章还没写好,留个草稿给自己看的)

    目前只是有一个大概的理解,先把自己感觉容易立即的概念放这里,等以后结合实际工作理解深刻了再来补充. 一.什么是Java反射机制?(多种定义) 1. JAVA反射机制是在运行状态中,对于任意一个类,都能 ...

  3. Java程序性能优化——让你的java程序更快、更稳定

    1.Java性能调优概述 1.1.Web服务器,响应时间.吞吐量是两个重要的性能参数. 1.2.程序性能的几个表现: 执行速度:程序的反映是否迅速,响应时间是否足够短 内存分配:分配是否合理,是否过多 ...

  4. java程序性能优化

    一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...

  5. 在 NetBeans IDE 6.0 中分析 Java 应用程序性能

    NetBeans IDE 6.0 包含一个强大的性能分析工具,可提供与应用程序运行时行为有关的重要信息.通过 NetBeans 性能分析工具,我们可以方便地在 IDE 中监控应用程序的线程状态.CPU ...

  6. [JAVA] java程序性能优化

    一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...

  7. Java程序性能优化读书笔记(一):Java性能调优概述

    程序性能的主要表现点: 执行速度:程序的反映是否迅速,响应时间是否足够短 内存分配:内存分配是否合理,是否过多地消耗内存或者存在内存泄漏 启动时间:程序从运行到可以正常处理业务需要花费多少时间 负载承 ...

  8. java的编程习惯影响程序性能

    在Java程序中,性能问题的大部分原因并不在于Java语言,而是在于程序本身. 养成良好的编程习惯非常重要,能够显著地提升程序性能. 尽量在合适的场合使用单例 使用单例可以减轻加载的负担,缩短加载的时 ...

  9. 跨多种环境部署 Gearman -改善应用程序性能和降低服务器负载

    您可能想要将工作扩散到一个大型机器群体中,或者想要在不同语言和环境之间共享功能,那么开放源码的 Gearman 服务可以让您轻松地将工作分布到网络中的其他机器.本文将介绍 Gearman 的一些典型应 ...

随机推荐

  1. mysql中delete和truncate区别

    delete和truncate区别如下: 一.灵活性:delete可以条件删除数据,而truncate只能删除表的所有数据: delete from table_test where ... trun ...

  2. python chunk模块

    chunk模块用于读取TIFF格式的文件,打开应该使用二进制模式 TIFF 标签图像文件格式 import chunk import chunk f=open('E:\\test.tiff','rb' ...

  3. 【转】五分钟读懂大数据核心MapReduce架构及原理

    什么是MapReduce Hadoop中的MapReduce是一个简单的软件框架,基于它写出的应用程序可以运行在由上千个商用机器组成的大型集群上,并以一种可靠容错式并行处理TB级数据 MapReduc ...

  4. python-正则表达式练习题

    1.匹配一行文字中的所有开头的字母内容 #coding=utf-8 import re s="i love you not because of who you are, but becau ...

  5. 多线程---ReentrantLock

    package com.test; import java.util.Collection; import java.util.concurrent.locks.Lock; import java.u ...

  6. Linux中Postfix邮件原理介绍(一)

    邮件相关协议 SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议, 工作在TCP的25端口.它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式 ...

  7. Tomcat8.5 升级tomcat版本导致出现异常,Base64不存在

    Tomcat8.5 升级tomcat版本导致出现异常,Base64不存在 原因分析: 由于tomcat由7升级到8.5导致Base64的引用路径错误,默认引用为8.5中的jar, 解决方案: 修改引用 ...

  8. 设置redis访问密码

    在服务器上,这里以linux服务器为例,为redis配置密码. 1.第一种方式 (当前这种linux配置redis密码的方法是一种临时的,如果redis重启之后密码就会失效,) (1)首先进入redi ...

  9. 20144303石宇森《网络对抗》注入shellcode和Return-to-libc攻击

    20144303石宇森<网络对抗>PC平台逆向破解 实验1:shellcode注入 实验基础 1.Linux下有两种基本构造攻击buf的方法:retaddr+nop+shellcode,n ...

  10. Beetl模板引擎入门教程

    最近项目中有个邮件发送的需求,不过要求发送的HTML格式的邮件.由于Beetl对java语言的良好支持和很好的性能,我们决定使用Beetl作为我们的模板引擎. Beetl官网已经有了很详细的教程,所以 ...