快速读取缓冲区而不复制

问题描述

所以我有这个 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,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 将存储在直接缓冲区上的数据复制到堆内存中,这是我不想要的,并且违背了使用堆外存储方式的目的。

方法 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]

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...