从Java函数返回两个值有效 [英] Returning two values from Java function efficiently

查看:139
本文介绍了从Java函数返回两个值有效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有人知道是否有办法从Java返回两个值(接近)零开销?我只是在寻找两个值 - 我有几个用例来处理一个字节数组(需要返回值和下一个起始位置)来尝试返回一个带有错误代码的值来做一些丑陋的修复 - 点计算并需要整个和小数部分。

Does anybody know if there is a way to return two values from Java with (close to) zero overhead? I'm only looking for two values - I have a couple use cases from processing an array of bytes (and need the return value and the next starting position) to trying to return a value with an error code to doing some ugliness with fixed-point calculations and need the whole and fractional part.

我不低于一些非常难看的黑客。功能很小,热点很高兴地介绍它。所以现在,我只需要让Hotspot基本上忽略任何对象创建或位移。

I'm not below some really ugly hacks. The function is small and Hotspot happily inlines it. So now, I just need to get Hotspot to basically elide any object creation or bit shifting.

如果我将返回的值限制为整数,我试图打包它们很长一段时间,但即使在内联之后,Hotspot似乎无法弄清楚所有的位移和面具都没有真正做任何事情,它很高兴地打包并解压缩到相同的值(显然,Hotspot的窥视孔优化器需要帮助的地方) )。但至少我没有创建一个对象。

If I restrict my returned values to ints, I 've tried to pack them into a long, but even after inlining, Hotspot cannot seem figure out that all the bit shifts and masks don't really do anything and it happily packs and unpacks the ints into the same values (clearly, a place where Hotspot's peephole optimizer needs help). But at least I'm not creating an object.

我更难的情况是当我需要返回的项目之一是参考而另一项是长期或另一个引用(对于int的情况,我想我可以压缩OOP并使用上面描述的位填充)。

My more difficult case is when one of the items I need to return is a reference and the other is a long or another reference (for the int case, I think I can compress the OOP and use the bit packing described above).

有没有人试图让Hotspot生成无垃圾这个代码?现在最糟糕的情况是我必须携带一个物体并传递它,但我想保持它自成一体。线程本地是昂贵的(哈希查找),它需要是可重入的。

Has anybody tried to get Hotspot to generate garbage-free code for this? Worst case right now is that I have to have a carry around an object and pass it in, but I'd like to keep it self contained. Thread Locals are expensive (hash lookups), and it needs to be reentrant.

推荐答案

-XX: + EliminateAllocations 优化(默认情况下在Java 8中为ON)可以正常工作。

-XX:+EliminateAllocations optimization (ON by default in Java 8) works fine for that.

每当你返回新对( a,b)在callee方法结束时立即在调用者中使用结果,如果被调用者被内联,JVM很可能会进行标量替换。

Whenever you return new Pair(a, b) right at the end of the callee method and use the result immediately in the caller, JVM is very likely to do a scalar replacement if the callee is inlined.

一个简单的实验表明返回一个对象几乎没有开销。这不仅是一种有效的方式,也是最具可读性的方式。

A simple experiment shows there's nearly no overhead in returning an object. This is not only an efficient way, but also the most readable one.

Benchmark                        Mode  Cnt    Score   Error   Units
ReturnPair.manualInline         thrpt   30  127,713 ± 3,408  ops/us
ReturnPair.packToLong           thrpt   30  113,606 ± 1,807  ops/us
ReturnPair.pairObject           thrpt   30  126,881 ± 0,478  ops/us
ReturnPair.pairObjectAllocated  thrpt   30   92,477 ± 0,621  ops/us

基准:

import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;

import java.util.concurrent.ThreadLocalRandom;

@State(Scope.Benchmark)
public class ReturnPair {
    int counter;

    @Benchmark
    public void manualInline(Blackhole bh) {
        bh.consume(counter++);
        bh.consume(ThreadLocalRandom.current().nextInt());
    }

    @Benchmark
    public void packToLong(Blackhole bh) {
        long packed = getPacked();
        bh.consume((int) (packed >>> 32));
        bh.consume((int) packed);
    }

    @Benchmark
    public void pairObject(Blackhole bh) {
        Pair pair = getPair();
        bh.consume(pair.a);
        bh.consume(pair.b);
    }

    @Benchmark
    @Fork(jvmArgs = "-XX:-EliminateAllocations")
    public void pairObjectAllocated(Blackhole bh) {
        Pair pair = getPair();
        bh.consume(pair.a);
        bh.consume(pair.b);
    }

    public long getPacked() {
        int a = counter++;
        int b = ThreadLocalRandom.current().nextInt();
        return (long) a << 32 | (b & 0xffffffffL);
    }

    public Pair getPair() {
        int a = counter++;
        int b = ThreadLocalRandom.current().nextInt();
        return new Pair(a, b);
    }

    static class Pair {
        final int a;
        final int b;

        Pair(int a, int b) {
            this.a = a;
            this.b = b;
        }
    }
}

这篇关于从Java函数返回两个值有效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆