Java 反射机制,速度提高 1000 倍

想让代码运行快1000倍,同时不改变复杂度,正如标题所说的,使用Java反射机制,可以让代码运行得更快。

首先来解释一下为什么会首先使用反射机制。

有一个接口(表示一个树节点)和一个实现这个接口的大量类(100+)。诀窍在于,树是异构的,每个节点类型可以有不同数量的子节点,或者以不同的方式存储它们。

我需要让代码能够在这样的组合树上运行起来。简单的方法是简单地向接口添加一个children()方法,并在每个节点中实现它。当然,这很繁琐,也很乏味。

相反,我注意到所有的子节点都是直接的字段,或者聚集在包含节点集合的字段中。所以可以用反射的方式写一小段代码,这也对每一个节点都适用!

我已经在Github上放了一个简化版的代码。我会把相关的部分联系起来。

初始化代码

这是我提出的第一版本代码:WalkerDemoSlowest.java。

它相当简单:获取节点类的方法,过滤掉那些不是getter的方法,然后只考虑返回节点或节点集合。调用这些方法,并在子节点上递归地调用walk方法。

如果我说这样的进展很慢,有人会感到惊讶吗?

缓存

有一个简单的调整,可以使它更快:使用缓存方法查找。

下面是缓存版本:WalkerDemoSlow.java

这和每个实现节点的类都是一样的,创建一个ClassData对象来缓存所有相关的getter方法,所以只需要查找一次,这会产生一个令人满意的10倍加速。

LambdaMetafactory 奇迹

不幸的是,这仍然太慢了。所以我向谷歌寻求帮助,发现了一个很有用的StackOverflow社区。

有答案建议使用LambdaMetafactory,这是一个标准的库类,它支持lambda语法调用。

细节在我看来有些模糊,但似乎通过使用这些工具,可以在代码中“打开编译器”,并优化反射机制来进行本机调用。这就是一种假设。

这是代码:walkerdemofast.java

现在,我的代码可以做到100倍的加速。然而,在写这篇文章的时候,想用一些代码片段来演示这个效果,但是没有成功。我试着给接口实现3个子类,并使用一些伪方法进行过滤,但还是没有效果。第二版和第三版的代码运行速度差不多。

我重新检查了原来的代码,一切看起来都很好。在原始代码中,树是通过解析一些源文件得到的抽象语法树(AST)。如果限制了前14个源文件的输入,我发现会得到不同的结果。

这些文件相对较短(几乎没有10行),语法简单。但仅仅有这些,第二和第三版代码仍会以同样的速度运行。但是在第15个文件中进行输入(少于100行),那么第二个版本的代码会花费36秒,而第三个版本代码会在0.2秒内完成,这是700倍的差异。

我的假设是,如果场景足够简单,优化器会注意到正在运行的代码并选择离开。在更复杂的情况下,它会耗尽优化预算,然后回到未优化的版本以及糟糕的性能状态。但是,优化器已经足够灵活,如果有一个能击败它的示例,那似乎是非常成功的。

LambdaMetafactory可能性

我有点好奇LambdaMetafactory会有什么样的可能性。在我的示例中,它会产生奇迹,因为反射调用比简单的缓存查找要昂贵得多。但它是否也能对常规代码进行优化处理呢?这似乎不太可能让megamorphic call sites提供帮助,因为编译的方法必须以某种方式检索,而查找的成本将使收益相形见绌。

但是,如何在运行组合代码时进行优化呢?可以提供数据结构,或者为数据结构提供解释器,并使用LambdaMetafactory“编译”它们。这是否足够智能呢,可以对给定数据结构的代码进行部分评估,从而将解释器转换成等价的“plain”代码?

顺便说一下,这正是Truffle框架所采用的方法,它在Graal VM上运行,所以这个想法肯定有一定的意义。可能暂时无法使用当前的JVM,因此需要修改GraalVM。

在任何情况下,都会尽量使一些功能成为一个库,可以在“常规程序”(非编译器)中使用。编写简单的解释器通常是解决一些问题的最简单方法。

文章出自http://geek.csdn.net/news/detail/236973

原文链接:

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java一日一条

10个实用的但偏执的Java编程技术

这就是为什么我们要采用“防御性编程”,即一些偏执习惯的原因。下面是我个人认为的10个最有用但偏执的Java编程技术。一起来看一看吧:

692
来自专栏葡萄城控件技术团队

当心那些有歧义的命名

关键点 “别人还能把这个名字理解成什么意思?”通过不断的问自己这个问题来积极检查每一个命名。 事实上,这种富有创造性的、不断尝试“错误理解”的方法,能够有...

1766
来自专栏吉浦迅科技

DAY37:阅读不同存储器的修饰符

1074
来自专栏Golang语言社区

无辜的goroutine

简介: 本文主要是针对一些对于goroutine的“指控”提出我自己的看法,特别是轩脉刃的一篇博客文章《论go语言中goroutine的使用》提出了gorout...

2845
来自专栏性能与架构

条件语句小技巧

“高性能javascript” 这本书中提到了一个“查找表”的概念,建议在有大量离散值要测试时,if-else 和 switch 都比使用查找表慢很多,依据是运...

2577
来自专栏企鹅号快讯

python中的时间处理大总结

北京 上海巡回站 | NVIDIA DLI深度学习培训 2018年1月26/1月12日 ? NVIDIA 深度学习学院 带你快速进入火热的DL领域 正文共485...

17610
来自专栏java一日一条

10个实用的但偏执的Java编程技术

在沉浸于编码一段时间以后(比如说我已经投入近20年左右的时间在程序上了),你会渐渐对这些东西习以为常。因为,你知道的……

512
来自专栏北京马哥教育

Python中的时间处理大总结

1244
来自专栏PhpZendo

如何使用 Laravel Collections 类编写神级代码

Laravel 提供了一些超赞的组件,在我看来,它是目前所有 Web 框架中提供组件支持最好的一个。它不仅提供了开箱即用的视图(views)、身份认证(auth...

472
来自专栏数据小魔方

左手用R右手Python系列之——字符串格式化进阶

关于R语言字符串格式化之前无论是专题还是案例教程中均有所涉及,今日这一篇之所以重提是因为又找到了一个很好用的字符串格式化包。 这个包的语法源于Python风格,...

28012

扫码关注云+社区