反射的性能差在哪里?

反射的性能差在哪里?,第1张

参考: https://www.jianshu.com/p/4e2b49fa8ba1

下图是一亿次循环的耗时:

反射的速度差异只在大量连续使用才能明显看出来,理论上100万次才会说反射很慢,对于一个单进单出的请求来说,反射与否根本差不了多少。

事实上各大框架注解,甚至业务系统中都在使用反射,不能因为慢就不用了。

在后台Controller中序列化请求响应信息大量使用注解,高并发就意味着连续百万级别调用反射成为可能,各大MVC框架都会着手解决这个问题,优化反射。

反射核心的是getMethod和invoke了,分析下两者的耗时差距,在一亿次循环下的耗时。

证明getMethod很耗时,所以说我们要优先优化getMethod,看看为什么卡?

getMethod最后直接调用native方法,无解了。想复写优化getMethod是不可能的了,官方没毛病。

但是我们可以不需要每次都getMethod啊,我们可以缓存到redis,或者放到Spring容器中,就不需要每次都拿了。

我们看下invoke的源码:

尴尬,最后还是native方法,依然没毛病。

invoke不像getMethod可以缓存起来重复用,没法优化。

所以这里需要引入ASM,并做了个工具库reflectAsm:

参考: https://blog.csdn.net/zhuoxiuwu/article/details/78619645 , https://github.com/EsotericSoftware/reflectasm

使用如下:

参考: https://blog.csdn.net/z69183787/article/details/51657771

invoke是没办法优化的,也没办法做到像直接调用那么快。所以大佬们脑洞大开,不用反射的invoke了。原理如下:

实际上reflectAsm是有个致命漏洞的,因为要生成文件,还得load进JVM,所以reflectAsm的getMethod特别慢:

虽然getMethod很慢,但是invoke的速度是到达了直接调用的速度了。

下面是反射优化的测试样例:

java反射需要将内存中的对象进行解析,涉及到与底层c语言的交互,速度会比较慢。

java反射得到的每一个Method都有一个root,不暴漏给外部,而是每次copy一个Method。具体的反射调用逻辑是委托给MethodAccessor的,而accessor对象会在第一次invoke的时候才创建,是一种lazy init方式。而且默认Class类会cache method对象。目前MethodAccessor的实现有两种,通过设置inflation,一个native方式,一种生成java bytecode方式。native方式启动快,但运行时间长了不如java方式,个人感觉应该是java方式运行长了,jit compiler可以进行优化。所以JDK6的实现,在native方式中,有一个计数器,当调用次数达到阀值,就会转为使用java方式。默认值是15。java方式的实现,基本和非反射方式相同。

反射肯定比直接调用慢

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

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

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

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

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

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

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

测试方法如下:

代码如下

复制代码

[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%总好过你请个牛逼的工程师来帮你做这种极限的优化,有一句话我觉得很对“工程师比服务器要昂贵的多”。如果你还非得跟我较劲,那么,没办法了,你程序对性能的要求已经超出了本文讨论的范畴,如果你真有这种需求了,我觉得你也没有必要看我这篇文章了,因为你已经足够牛逼到对系统语言都有深入了解了。

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

总结

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

反射大概比直接调用慢50~100倍,但是需要你在执行100万遍的时候才会有所感觉

判断一个函数的性能,你需要把这个函数执行100万遍甚至1000万遍

如果你只是偶尔调用一下反射,请忘记反射带来的性能影响

如果你需要大量调用反射,请考虑缓存。

你的编程的思想才是限制你程序性能的最主要的因素


欢迎分享,转载请注明来源:优选云

原文地址:https://54852.com/hy/1002002.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-08-05
下一篇2023-08-05

随机推荐

  • 美肤宝有哪些系列产品

    汉方花本系列:花之肽源萃雪颜系列,花之肽玉露润颜系列,花之肽净透清颜系列,花之肽冰花舒颜系列,花之肽卓颜新生系列,花之肽时空防护系列汉方经典系列:宫廷验方系列,如玉七白系列,凝眸玉萃系列,汉草基础系列,五珍还幼系列汉方草本系列:雪肌方,润肌

    2023-12-14
    44900
  • 兰蔻小黑瓶多少钱

    兰蔻小黑瓶价格表兰蔻小黑瓶眼霜15ml 精华眼膜霜 38500元兰蔻小黑瓶套装 小黑瓶肌底液50ml+眼膜霜15ml 112914元Lancome兰蔻小黑瓶精华肌底液50ml76507元兰蔻美颜活肤液精华肌底液小黑瓶7ml480

    2023-12-14
    31000
  • 意大利品牌歌丽诗最强效的美白祛斑霜怎样

    科学的祛斑方式并不是单一的祛斑方式,因为色斑的形成原因是多方面的。所以单方面的祛斑方式是不科学的。祛斑单单只依靠一种祛斑产品是不能够把色斑去除的,首先要分析身子色斑形成的具体原因,根据色斑形成的原因选择适合自己的祛斑方式和正规的祛斑产品才是

    2023-12-14
    32900
  • 理肤泉蓝标防晒霜怎么样它的使用测评如何

    护肤的最后一步就是防晒,防晒的重要性应该不用小编多说了,预防皮肤光老化问题的出现,色斑等都很影响美观。那么理肤泉蓝标防晒霜怎么样?理肤泉蓝标防晒霜测评。理肤泉蓝标防晒霜怎么样无酒精、无香料!质地是乳白色的,抹开吸收以后马上就会成膜。完全哑光

    2023-12-14
    22800
  • 美妆星空是正品吗

    美妆星空是正品。宁波市江北美妆星空化妆品店,成立于2017年,位于浙江省宁波市,是一家以从事零售业为主的企业,经营范围为日用品,化妆品零售,有市场监管局监督产品,根据查证相关资料信息美妆星空的产品是正品。2022年,这些彩妆的坑你必须要知道

    2023-12-14
    29800
  • 彩妆品类都些什么

    彩妆品类有清洁霜、洗面奶、浴剂,面霜、蜜化妆水,面膜胭脂,口红,眼影等。按使用部位分,肤用化妆品指面部及皮肤用化妆品。这类化妆品如各种面霜、浴剂,发用化妆品指头发专用化妆品,这类化妆品如香波、摩丝、喷雾发胶等美容化妆品主要指面部美容产品,也

    2023-12-14
    19300
  • 什么是bb霜

    什么是bb霜什么是bb霜,每一个女人在开始学习化妆的时候,肯定遇到过bb霜这个东西的,由于刚接触化妆不久,什么是bb霜并不太了解的,我为大家整理好了什么是bb霜的相关资料,一起来看看吧。什么是b

    2023-12-13
    22400
  • 羽西化妆品怎么样啊

    于的护肤品是民用护肤品中最大的品牌。玉溪在国际上属于中低档,在国货上属于中高档。中药是包装和所有产品中的主要产品。虽然已经收购了玉溪,但是其产品的外包装依然有很浓的中国风,在国货中属于中端和高端。羽西的护肤品是平民护肤品中最大的品牌,比韩国

    2023-12-13
    21200
  • 宗彩国际化妆品有限公司怎么样

    公司实力雄厚。宗彩国际化妆品有限公司占地面积为400平方米,有正式员工110人,具有前沿的科研水平,致力于为更多的消费者研究出更优质的化妆品。宗彩国际化妆品有限公司成立于2021年,业务范围包括研发和生产美容化妆品,营销和品牌推广,化妆品的

    2023-12-13
    22200

发表评论

登录后才能评论
保存