我正在编写一些可调用的代码,Field.set
并且执行Field.get
了数千次。显然,由于反射,这非常慢。
我想看看是否可以MethodHandle
在Java
7中使用以提高性能。到目前为止,这里是我所拥有的:
代替field.set(pojo, value)
,我在做:
private static final Map<Field, MethodHandle> setHandles = new HashMap<>();
MethodHandle mh = setHandles.get(field);
if (mh == null) {
mh = lookup.unreflectSetter(field);
setHandles.put(field, mh);
}
mh.invoke(pojo, value);
但是,这似乎并不比使用反射的Field.set调用更好。我在这里做错什么了吗?
我读到使用invokeExact
可能会更快,但是当我尝试使用它时,得到了java.lang.invoke.WrongMethodTypeException
。
有谁成功地优化了对Field.set或Field.get的重复调用?
2015-06-01:已更新,以反映@JoeC对句柄为静态的另一种情况的评论。 还更新为最新的JMH,并在现代硬件上重新运行。结论几乎保持不变。
请进行适当的基准测试,对于JMH来说并不是很难。一旦这样做,答案就显而易见了。它还可以展示的正确用法invokeExact
(需要目标/源1.7进行编译和运行):
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(3)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread)
public class MHOpto {
private int value = 42;
private static final Field static_reflective;
private static final MethodHandle static_unreflect;
private static final MethodHandle static_mh;
private static Field reflective;
private static MethodHandle unreflect;
private static MethodHandle mh;
// We would normally use @Setup, but we need to initialize "static final" fields here...
static {
try {
reflective = MHOpto.class.getDeclaredField("value");
unreflect = MethodHandles.lookup().unreflectGetter(reflective);
mh = MethodHandles.lookup().findGetter(MHOpto.class, "value", int.class);
static_reflective = reflective;
static_unreflect = unreflect;
static_mh = mh;
} catch (IllegalAccessException | NoSuchFieldException e) {
throw new IllegalStateException(e);
}
}
@Benchmark
public int plain() {
return value;
}
@Benchmark
public int dynamic_reflect() throws InvocationTargetException, IllegalAccessException {
return (int) reflective.get(this);
}
@Benchmark
public int dynamic_unreflect_invoke() throws Throwable {
return (int) unreflect.invoke(this);
}
@Benchmark
public int dynamic_unreflect_invokeExact() throws Throwable {
return (int) unreflect.invokeExact(this);
}
@Benchmark
public int dynamic_mh_invoke() throws Throwable {
return (int) mh.invoke(this);
}
@Benchmark
public int dynamic_mh_invokeExact() throws Throwable {
return (int) mh.invokeExact(this);
}
@Benchmark
public int static_reflect() throws InvocationTargetException, IllegalAccessException {
return (int) static_reflective.get(this);
}
@Benchmark
public int static_unreflect_invoke() throws Throwable {
return (int) static_unreflect.invoke(this);
}
@Benchmark
public int static_unreflect_invokeExact() throws Throwable {
return (int) static_unreflect.invokeExact(this);
}
@Benchmark
public int static_mh_invoke() throws Throwable {
return (int) static_mh.invoke(this);
}
@Benchmark
public int static_mh_invokeExact() throws Throwable {
return (int) static_mh.invokeExact(this);
}
}
在1x4x2 i7-4790K,JDK 8u40,Linux x86_64上产生:
Benchmark Mode Cnt Score Error Units
MHOpto.dynamic_mh_invoke avgt 25 4.393 ± 0.003 ns/op
MHOpto.dynamic_mh_invokeExact avgt 25 4.394 ± 0.007 ns/op
MHOpto.dynamic_reflect avgt 25 5.230 ± 0.020 ns/op
MHOpto.dynamic_unreflect_invoke avgt 25 4.404 ± 0.023 ns/op
MHOpto.dynamic_unreflect_invokeExact avgt 25 4.397 ± 0.014 ns/op
MHOpto.plain avgt 25 1.858 ± 0.002 ns/op
MHOpto.static_mh_invoke avgt 25 1.862 ± 0.015 ns/op
MHOpto.static_mh_invokeExact avgt 25 1.859 ± 0.002 ns/op
MHOpto.static_reflect avgt 25 4.274 ± 0.011 ns/op
MHOpto.static_unreflect_invoke avgt 25 1.859 ± 0.002 ns/op
MHOpto.static_unreflect_invokeExact avgt 25 1.858 ± 0.002 ns/op
…这表明在这种特定情况下,MH实际上比反射快得多(这是因为针对私有字段的访问检查是在查找时而不是在调用时完成的)。dynamic_*
情况模拟了当MethodHandles
和/或Fields
不是静态已知(例如从中拉出Map<String, MethodHandle>
或类似的东西)时的情况。相反,static_*
情况是调用程序是静态已知的。
请注意,在dynamic_*
某些情况下,反射性能与MethodHandles相当,这是因为反射在JDK
8中得到了进一步的优化(因为实际上,您不需要访问检查即可读取自己的字段),因此答案可能是“公正”切换到JDK 8;)
static_*
案例甚至更快,因为MethoHandles.invoke
调用被积极地内联。这消除了MH情况下的部分类型检查。但是,在反思的情况下,仍然存在快速检查,因此,它落后了。
我正在编写一些调用和几千次的代码。显然这是非常缓慢的,因为反射。 我想看看是否可以在Java7中使用来提高性能。到目前为止,我有以下资料: 不是,而是: 但是,这似乎并不比使用反射的field.set调用执行得更好。我是不是做错什么了? 我读到使用可能更快,但当我尝试使用它时,我得到了一个。 是否有人成功地优化了对field.set或field.get的重复调用?
我有一个名为Emails的列族,我正在将邮件保存到这个CF中,编写5000封邮件需要100秒。 我使用的是i3处理器,8gb内存。我的数据中心有6个节点,复制因子=2。 我们存储在卡桑德拉中的数据大小会影响性能吗?影响写入性能的所有因素是什么,如何提高性能? 预先感谢..
问题内容: 我在公司中多次设计数据库。为了提高数据库的性能,我只寻找标准化和索引。 如果要求您提高数据库的性能,该数据库包含大约250个表以及一些具有数百万个记录的表,那么您将寻找什么不同的东西? 提前致谢。 问题答案: 优化逻辑设计 逻辑级别是关于查询和表本身的结构。首先尝试最大程度地发挥这一作用。目标是在逻辑级别上访问尽可能少的数据。 拥有最高效的SQL查询 设计支持应用程序需求的逻辑架构(例
问题内容: 我有2张桌子,和。用户可以有很多游戏。我需要所有有人数的人,以及他们的人数(有专栏的)。 附言:我需要将所有数据加载到管理表中。由于游戏太多。我决定对数据进行分页和限制。但是,甚至限制以下查询也需要花费相同的时间。如何更好地查询? 问题答案: 您可以在下面尝试使用表达式
我有一个简单的任务:确定需要多少字节来将某个数字(字节数组长度)编码到字节数组并编码最终值(实现本文:编码长度和值字节)。 最初我写了一个快速完成任务的方法: 这是一段旧代码,编写方式很糟糕。 现在我正在尝试使用按位运算符或类来优化代码。这是按位版本的示例: 以及类的最终实现: 所有方法都按预期工作。我使用秒表类页面中的一个示例来衡量性能。性能测试让我惊讶。我的测试方法执行了1000次该方法的运行
我明白为什么C 11中的类型提高了正确性和可运维性。我读到它也可以提高性能(赫伯·萨特的《几乎总是自动》),但我错过了一个很好的解释。 如何提高性能