【问题标题】:RandomAccessFile is slow on first accessRandomAccessFile 在第一次访问时很慢
【发布时间】:2017-08-09 06:44:25
【问题描述】:

我目前正在使用 RandomAccessFile 并遇到一个奇怪的现象。 我正在访问一个 1.1TB 大且仅包含等于 00000000 的字节的文件。

我通过以下方式实现了 RandomAccessFile:

RandomAccessFile raf = new RandomAccessFile(new File("./db.bin"),"rw");

所以我的程序正在生成一个代表 BIT 位置的 Long 值的大列表,一旦达到 1000 个条目,它会将数据刷新到文件中:

    public void flush() {
       for( long l : lLongs ) {
           lseek = Long.divideUnsigned(l, 8L);
           raf.seek( lseek );
           byte b = raf.readByte();
           raf.seek( lseek );
           raf.writeByte( editByte(b,(int)l % 8) );
       }
       raf.close();
    }

    public byte editByte( byte b, int iBit ) {
      if( !isSet(b,iBit) ) {
        b = (byte)(b + Math.pow( 2, iBit));
      }
      return b;
    }

    boolean isSet(byte value, int bit){
       return (value >> bit & 1) == 1;
    }

现在我想知道为什么需要这么长时间?对于 1000 个条目,平均需要 15 秒。 但是如果我取消我的程序并重新启动它,我将只需要 5ms 输入 1000 个条目(多头保持相同)

这是为什么呢?有人可以帮我解决这个问题吗?

【问题讨论】:

  • 这是一个二进制文件,不是文本文件,所以它不应该有 .txt 扩展名。
  • 固定文件扩展名
  • 答案在于缓存启动。第二次,操作系统缓存了最近读取的文件。

标签: java io randomaccessfile


【解决方案1】:

逻辑上的解释是第一次启动需要实际读取文件,第二次启动从内存缓存中获取文件,这样快得多。

也是第2次,如果我没看错就不用写数据了。

如果你想得到更好的东西,你可以尝试有顺序的东西,比如:

private static final int CHUNK_SIZE=512*8*1024;  // 4Mb chunk

private RandomAccessFile raf; 
private long currentChunk=-1;
private byte[] chunk=new byte[CHUNK_SIZE];

public void flush() throws Exception{
    raf = new RandomAccessFile(new File("./db.bin"),"rw");
    List<Long> c=something();

    c.stream().sorted().forEach(this::process);

    saveChunk();
}

public void process(long l) {
    try {
        if (l/8/CHUNCK_SIZE!=currentChunk) {
            saveChunk();
            loadNextChunk();
        }

        long posInMem=(l/8) - (CHUNK_SIZE*currentChunk);
        byte b=chunk[(int)posInMem];
        chunk[(int)posInMem]=editByte(b,(int)l % 8);
    }catch(Exception e) {
        e.printStackTrace();
    }
}

private void loadNextChunk()throws Exception {
    currentChunk++;
    raf.seek(currentChunk*CHUNK_SIZE);
    raf.readFully(chunk, 0, CHUNK_SIZE);
}

private void saveChunk() throws Exception {
    if (currentChunk<0)return;
    raf.seek(currentChunk*CHUNK_SIZE);
    raf.write(chunk, 0, CHUNK_SIZE);
}

【讨论】:

  • 取消前您处理了多少数据?到现在为止它会更快然后第二次变慢吗? (也是第二次不用写了!)
  • 我处理了 500000 个条目,它会冲到 75000 个条目,然后会减慢到 1000 个条目的 700 毫秒,这仍然比 1000 个条目的 15 秒快。
  • 运行此程序时的 I/O 等待状态是什么? (第一次和第二次)。你可以按顺序处理文件,这样你就不需要写太多数据了吗? (排序很长,然后在 4096*n 和 4096*(n+1) 之间花费很长时间读取磁盘上的位置(512 字节顺序)然后写入这些位。)你会减少很多你的 IO
  • 我的赌注也会放在 FS 缓存上。并不意味着整个文件都被缓存了,但有足够的块来产生影响。
  • 我的等待状态大约是 20-25%,我应该如何依次浏览文件?我刚刚看到您对缓存的看法是正确的......
猜你喜欢
  • 2015-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多