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 条评论
登录 后参与评论

相关文章

来自专栏转载gongluck的CSDN博客

MFC ActiveX (ocx)控件的开发

前言 ActiveX是Microsoft对于一系列策略性面向对象程序技术和工具的称呼,其中主要的技术是组件对象模型(COM)。 ActiveX控件是一种实现...

4577
来自专栏Coco的专栏

不受控制的 position:fixed

1244
来自专栏前端黑板报

再谈异步

小亲冈 爱屋吉屋 前端开发工程师 按顺序完成异步操作 实际开发中,经常遇到一组异步操作,需要按照顺序完成。比如,展示页面中有上中下三个部分,每一部分通过一个接口...

1935
来自专栏小詹同学

为什么你的Python代码质量如此不堪……

作者:笑虎(Python爱好者,关注爬虫、数据分析、数据挖掘、数据可视化等) 原文链接:http://codebay.cn/post/7953.html

764
来自专栏nummy

Django User模型扩展

通常情况下,Django提供的User模型能够满足我们大部分的需求,但是有时候我们需要给User添加一些格外的功能和信息。

411
来自专栏Coding01

简述我所理解的 PHP Trait

在常规的 PHP 开发中,我们都习惯于先编写一个通用的基类,实现基本的功能,然后扩展这个基类,创建更具体的子类,直接从父类继承实现。很多编程语言都使用这个继承层...

905
来自专栏社区的朋友们

在共享内存实现 Redis(下)

从实现方式入手,设计了一种综合二者优点的方案:将 Redis 做成数据逻辑分离,数据存放共享内存,进程只负责存储逻辑,同时解决 Redis 长命令卡顿和 for...

2700
来自专栏python成长之路

Pygame常用方法

2755
来自专栏瓜大三哥

UVM(十二)之各register model

UVM(十二)之各register model 1. register model的必要性 考虑一个问题,当验证平台向DUT发了某些激励后,我们期望DUT中的某...

22310
来自专栏用户2442861的专栏

Qt 常用类 (9)—— QWidget

http://blog.csdn.net/hmsiwtv/article/details/7562015

671

扫码关注云+社区