与仅使用 lambda 相比,lambdametafactory 创建速度相当慢

问题描述 投票:0回答:1
@Benchmark
public void testLambdaGeneration(Blackhole bh) {
    Function<Object, Object> function = a -> {
        if(a instanceof Alpha alpha) {
            return alpha.primitiveInt();
        }else {
            throw new RuntimeException();
        }
    };
    bh.consume(function);
}

@Benchmark
public void testManualGeneration(Blackhole bh) {
    try{
        MethodHandle mh = MethodHandles.lookup().findVirtual(Alpha.class, "primitiveInt", MethodType.methodType(int.class));
        MethodType type = mh.type();
        type = type.changeReturnType(Integer.class);
        CallSite callSite = LambdaMetafactory.metafactory(MethodHandles.lookup(),
                "apply",
                MethodType.methodType(Function.class),
                type.erase(), mh, type);
        Function<Object, Object> f = (Function<Object, Object>) callSite.getTarget().invokeExact();
        bh.consume(f);
    }catch (Throwable e) {
        throw new RuntimeException("Unreached");
    }
}

我想使用 lambdametafactory 创建构造函数、getter 和 setter 方法以供反射使用,生成的 Function<> 与直接调用一样快,这极大地满足了我的需求。然而,当我使用上面的代码来测试 lambdafactory 和纯 lambda 之间的生成性能时,结果却相当不乐观:

LambdaTest.testLambdaGeneration  avgt   50      0.574 ±     0.015  ns/op
LambdaTest.testManualGeneration  avgt   50  29424.815 ± 20402.801  ns/op

我认为lambda函数内部会使用LambdaMetafactory,所以结果应该是一致的,但实际结果确实让我震惊。

我的代码有什么问题吗?如何提高 LambdaMetafactory.metafactory() 的性能以匹配纯 lambda 生成?

java lambda reflection methodhandle lambda-metafactory
1个回答
0
投票

你可以试试我写的这个版本。

private Function<Object, Object> cachedFunction;

@Setup
public void setup() {
    try {
        MethodHandle mh = MethodHandles.lookup().findVirtual(Alpha.class, "primitiveInt", MethodType.methodType(int.class));
        MethodType type = mh.type().changeReturnType(Integer.class);
        CallSite callSite = LambdaMetafactory.metafactory(MethodHandles.lookup(),
                "apply",
                MethodType.methodType(Function.class),
                type.erase(), mh, type);
        cachedFunction = (Function<Object, Object>) callSite.getTarget().invokeExact();
    } catch (Throwable e) {
        throw new RuntimeException("Setup failed", e);
    }
}

@Benchmark
public void testCachedManualGeneration(Blackhole bh) {
    bh.consume(cachedFunction.apply(new Alpha()));
}
© www.soinside.com 2019 - 2024. All rights reserved.