无需复制即可快速读取缓冲区

Reading a Buffer Fast without Copying

所以我有这个 MappedByteBuffer,其中存储了一个 int 数组(从文件中读取)。

public static void read(String loc) {
    try (FileChannel fileChannel = (FileChannel) Files.newByteChannel(
            Paths.get(loc), EnumSet.of(StandardOpenOption.READ))) {
        MappedByteBuffer mappedByteBuffer = fileChannel
                .map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
        if (mappedByteBuffer != null) {
            IntBuffer ib = mappedByteBuffer.asIntBuffer();
            mappedByteBuffer.clear();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

现在,当我想从 Buffer 中读取 int 数组并在我的代码中使用它时,我必须采用以下两种方式之一:

方式一:(将缓冲区(ints)的内容复制到一个int数组中)

int[] ar = new int[ib.capacity];
ib.get(ar);
int int_at_index_0 = ar[0]; 

方式二:(直接从缓冲区读取)

ib.get(0); //reads int at index 0 directly

现在据我了解,方式 1 将存储在直接缓冲区中的数据复制到堆内存中,这是我不想要的,并且违背了使用 Off- 的目的堆存储方式。

方法 2 get(index) 方法花费的时间太长,如下面的数据所示:

int[] 数组读取:(从 ByteBuffer 复制)

ar[0] 需要 1928 纳秒。

直接从 ByteBuffer 读取:

ib.get(0) 需要 18915 纳秒。

差别很大。

有谁知道我如何从 directbuffer/mappedbytebuffer FAST 读取并且不复制到堆内存(将其保存在堆外)。

您可以按照 Guava 人员在 ThreadLocal 中存储一个小缓冲区(1024 字节)的方式进行操作,如果足够就使用它并且永远不要在 TL 中放置更大的缓冲区。

只要它可以满足大多数请求,它就可以正常工作。没有一些真正的测试,很难说它是否有帮助。

Google Guava ByteSource 似乎是在内存中缓冲的不错选择。与 ByteArrayOutputStream 或 ByteArrayList(来自 Colt 库)等实现不同,它不会将数据合并到一个巨大的字节数组中,而是单独存储每个块。一个例子:

List<ByteSource> result = new ArrayList<>();
try (InputStream source = httpRequest.getInputStream()) {
    byte[] cbuf = new byte[CHUNK_SIZE];
    while (true) {
        int read = source.read(cbuf);
        if (read == -1) {
            break;
        } else {
            result.add(ByteSource.wrap(Arrays.copyOf(cbuf, read)));
        }
    }
}
ByteSource body = ByteSource.concat(result);

以后可以随时将 ByteSource 作为 InputStream 读取:

InputStream data = body.openBufferedStream();



[Also you might check this out ][1]