DataInputStream数据读取 Vs ByteBuffer数据读取的巨大性能差距

背景:

今天在查找一个序列化和反序列化相关的问题时,意外发现使用DataInputStream读取和ByteBuffer读取之间性能相差巨大,本文就来记录下这两者在读取整数类型时的性能差异,以便在平时使用的过程中引起注意

DataInputStream数据读取 Vs ByteBuffer数据读取

我们会分别使用DataInputStream和ByteBuffer读取不同长度的字节数组,分别测试读取Short,Int,Long三类整数,然后分别看一下他们的性能

性能测试代码如下:

package org.example.jmh.deserialize;

import static java.util.concurrent.TimeUnit.MICROSECONDS;
import static org.example.jmh.deserialize.DataUtil.createByteArray;

import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

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

@Warmup(iterations = 2, time = 2)
@Measurement(iterations = 3, time = 10)
@Fork(1)
@OutputTimeUnit(MICROSECONDS)
public class ByteBufferVsByteArrayDataInputBenchmark {


    @State(Scope.Benchmark)
    public static class ByteBufferBackedDataInputState {

        ByteBuffer buffer;
        DataInput dataInput;
        @Param({"8", "32", "64", "128"})
        int size;

        byte[] data;

        public void createData() {
            this.data = createByteArray(size);
        }

        @Setup(Level.Trial)
        public void init() {
            createData();
            this.buffer = ByteBuffer.wrap(data);
            this.dataInput = new BufferDataInput(buffer);
        }

        void reset() {
            buffer.position(0);
        }
    }

    @State(Scope.Benchmark)
    public static class StreamBackedDataInpuState {

        ByteArrayInputStream bis;
        DataInput dataInput;

        @Param({"8", "32", "64", "128"})
        int size;

        byte[] data;

        public void createData() {
            this.data = createByteArray(size);
        }

        @Setup(Level.Trial)
        public void init() {
            createData();
            this.bis = new ByteArrayInputStream(data);
            this.dataInput = new DataInputStream(bis);
        }

        void reset() {
            bis.reset();
        }
    }

    @Benchmark
    public void streamBackedDataInputReadShort(StreamBackedDataInpuState state, Blackhole bh) throws IOException {
        DataInput input = state.dataInput;
        int size = state.size;
        int pos = 0;
        while (pos < size) {
            bh.consume(input.readShort());
            pos += 2;
        }
        state.reset();
    }

    @Benchmark
    public void bufferBackedDataInputReadShort(ByteBufferBackedDataInputState state, Blackhole bh) throws IOException {
        DataInput input = state.dataInput;
        int size = state.size;
        int pos = 0;
        while (pos < size) {
            bh.consume(input.readShort());
            pos += 2;
        }
        state.reset();
    }

    @Benchmark
    public void streamBackedDataInputReadInt(StreamBackedDataInpuState state, Blackhole bh) throws IOException {
        DataInput input = state.dataInput;
        int size = state.size;
        int pos = 0;
        while (pos < size) {
            bh.consume(input.readInt());
            pos += 4;
        }
        state.reset();
    }

    @Benchmark
    public void bufferBackedDataInputReadInt(ByteBufferBackedDataInputState state, Blackhole bh) throws IOException {
        DataInput input = state.dataInput;
        int size = state.size;
        int pos = 0;
        while (pos < size) {
            bh.consume(input.readInt());
            pos += 4;
        }
        state.reset();
    }

    @Benchmark
    public void streamBackedDataInputReadLong(StreamBackedDataInpuState state, Blackhole bh) throws IOException {
        DataInput input = state.dataInput;
        int size = state.size;
        int pos = 0;
        while (pos < size) {
            bh.consume(input.readLong());
            pos += 8;
        }
        state.reset();
    }

    @Benchmark
    public void bufferBackedDataInputReadLong(ByteBufferBackedDataInputState state, Blackhole bh) throws IOException {
        DataInput input = state.dataInput;
        int size = state.size;
        int pos = 0;
        while (pos < size) {
            bh.consume(input.readLong());
            pos += 8;
        }
        state.reset();
    }

    public static class BufferDataInput implements DataInput {

        private final ByteBuffer data;

        public BufferDataInput(ByteBuffer data) {
            this.data = data;
        }

        @Override
        public void readFully(byte[] bytes) {}

        @Override
        public void readFully(byte[] bytes, int i, int i1) {}

        @Override
        public int skipBytes(int i) {
            data.position(data.position() + i);
            return data.position();
        }

        @Override
        public boolean readBoolean() {
            return data.get() != 0;
        }

        @Override
        public byte readByte() {
            return data.get();
        }

        @Override
        public int readUnsignedByte() {
            return data.get() & 0xFF;
        }

        @Override
        public short readShort() {
            return data.getShort();
        }

        @Override
        public int readUnsignedShort() {
            return data.getShort() & 0xffff;
        }

        @Override
        public char readChar() {
            return data.getChar();
        }

        @Override
        public int readInt() {
            return data.getInt();
        }

        @Override
        public long readLong() {
            return data.getLong();
        }

        @Override
        public float readFloat() {
            return data.getFloat();
        }

        @Override
        public double readDouble() {
            return data.getDouble();
        }

        @Override
        public String readLine() {
            return null;
        }

        @Override
        public String readUTF() {
            return null;
        }
    }


}

jmh的测试结果:
DataInputStream数据读取 Vs ByteBuffer数据读取的巨大性能差距_第1张图片
从结果可以看出,不论是读取Short,Int还是Long,ByteBuffer都比DataInputStream有很大的性能优势,大概3-4倍的差异,那么你知道造成这种性能差距的原因是什么吗,留个悬念

你可能感兴趣的:(java性能,开发语言,java)