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后端技术栈

关于Java代码优化的N条建议!

本文是作者:五月的仓颉 结合自己的工作和平时学习的体验重新谈一下为什么要进行代码优化。在修改之前,作者的说法是这样的:

1342
来自专栏Golang语言社区

Golang语言--资源自动回收技术

Go语言作为一个现代化的编程语言以及支持垃圾内存的自动回收特性(GC). 我们现在关注的是非内存资源的自动回收技术. 局部资源的管理 在讨论Go语言解决方案之前...

4188
来自专栏诸葛青云的专栏

学了指针没学动态内存一切都白搭!C语言基础教程之内存管理

本文将讲解 C 中的动态内存管理。C 语言为内存的分配和管理提供了几个函数。这些函数可以在<stdlib.h>头文件中找到。

1160
来自专栏Android 开发者

Android 开发者如何函数式编程 (三)

3658
来自专栏Java技术栈

一个正则表达式酿成的惨案…

导读:正则表达式是程序员经常使用的工具之一。本文作者通过一个正则表达式的陷阱,先深入剖析了出现问题的原因,后给出怎么处理这类问题的方法。最后还给出了一些检测常见...

971
来自专栏达摩兵的技术空间

js代码优化日常001

本文开始针对项目中总结出来的关于js基础知识的代码优化技巧进行每个细节点的分析,后续还会针对某个专题的分析。

1913
来自专栏企鹅号快讯

编程语言学啥?当然首选Python啦!千字长文教你如何入门Python!

1.1 流程控制之for循环 ? 1.2 开发工具IDE 1.2.1 为何要用IDE ? 很多语言都有比较流行的开发工具,比如JAVA 的Eclipse, C#...

4546
来自专栏difcareer的技术笔记

Android智能指针

网上已经有很多分析智能指针的文章了,讲得不错的是:Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析。本文尽量从不分析代码的角度,将And...

834
来自专栏思考的代码世界

Python编程从入门到实践之类|第10天

面向对象编程是最有效的软件编写方法之一。在面向对象编程中,你编写表示现实世界中的事物和情景的类,并基于这些类来创建对象。编写类时,你定义一大类对象都有的通用行为...

3134
来自专栏向治洪

python 日期与时间

###python 日期与时间 (time,datetime包) [toc] #####概述 在应用程序的开发过程中,难免要跟日期、时间处理打交道。如:记录一个...

42810

扫码关注云+社区

领取腾讯云代金券