gpt4 book ai didi

java - 如何提高 Field.set 的性能(可能使用 MethodHandles)?

转载 作者:IT老高 更新时间:2023-10-28 20:47:42 33 4
gpt4 key购买 nike

我正在编写一些调用 Field.set 的代码和 Field.get 成千上万次。显然这很慢,因为 reflection .

我想看看我是否可以使用 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:更新以反射(reflect) @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 确实比反射快得多(这是因为对私有(private)字段的访问检查是在查找时完成的,而不是在调用时完成的)。 dynamic_*案例模拟 MethodHandles 时的情况和/或 Fields不是静态已知的,例如来自 Map<String, MethodHandle>或类似的东西。相反,static_*情况是调用者是静态已知的。

请注意,反射性能与 dynamic_* 中的 MethodHandles 相当在这种情况下,这是因为反射在 JDK 8 中得到了进一步优化(因为实际上,您不需要访问检查来读取自己的字段),所以答案可能是“只是”切换到 JDK 8 ;)

static_*案例甚至更快,因为 MethoHandles.invoke调用是积极内联的。这消除了 MH 案例中的部分类型检查。但是,在反射情况下,仍然存在快速检查,因此它落后了。

关于java - 如何提高 Field.set 的性能(可能使用 MethodHandles)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22244402/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com