如何用Java写入磁盘(使用刷新)并保持性能?

Jac*_*cob 5 c java performance disk

使用以下代码作为基准,系统可以在几分之一秒内将10,000行写入磁盘:

void withSync() {
    int f = open( "/tmp/t8" , O_RDWR | O_CREAT );
    lseek (f, 0, SEEK_SET );
    int records = 10*1000;
    clock_t ustart = clock();
    for(int i = 0; i < records; i++) {
        write(f, "012345678901234567890123456789" , 30);
        fsync(f);
    }
    clock_t uend = clock();
    close (f);
    printf("   sync() seconds:%lf   writes per second:%lf\n", ((double)(uend-ustart))/(CLOCKS_PER_SEC), ((double)records)/((double)(uend-ustart))/(CLOCKS_PER_SEC));
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,可以写入10,000条记录并在几分之一秒内刷新到磁盘,输出如下:

sync() seconds:0.006268   writes per second:0.000002
Run Code Online (Sandbox Code Playgroud)

在Java版本中,写入10,000条记录需要4秒多的时间.这仅仅是Java的限制,还是我错过了什么?

public void testFileChannel() throws IOException {
    RandomAccessFile raf = new RandomAccessFile(new File("/tmp/t5"),"rw");
    FileChannel c = raf.getChannel();
    c.force(true);
    ByteBuffer b = ByteBuffer.allocateDirect(64*1024);
    long s = System.currentTimeMillis();
    for(int i=0;i<10000;i++){            
        b.clear();
        b.put("012345678901234567890123456789".getBytes());
        b.flip();
        c.write(b);
                    c.force(false);
    }
    long e=System.currentTimeMillis();
    raf.close();
    System.out.println("With flush "+(e-s));

}
Run Code Online (Sandbox Code Playgroud)

返回此:

With flush 4263
Run Code Online (Sandbox Code Playgroud)

请帮助我了解在Java中将记录写入磁盘的正确/最快方法.

注意:我将该RandomAccessFile类与a结合使用,ByteBuffer因为最终我们需要对此文件进行随机读/写访问.

Pet*_*rey 5

实际上,我很惊讶测试并不慢.强制行为取决于操作系统,但广义上它会强制数据到磁盘.如果你有一个SSD,你可以达到每秒40K的写入速度,但是使用硬盘驱动器则不会.在C示例中,它显然没有将数据提交到磁盘,因为即使最快的SSD也不能执行超过235K的IOPS(制造商保证它不会比这更快:D)

如果您每次都需要提交到磁盘的数据,您可能会觉得它很慢并且完全取决于硬件的速度.如果您只需要刷新到操作系统的数据,如果程序崩溃但操作系统没有,您将不会丢失任何数据,您可以无需强制写入数据.更快的选择是使用内存映射文件.这将为您提供随机访问,而无需每个记录的系统调用.

我有一个库Java Chronicle,它可以每秒读取/写入5-20百万条记录,文本或二进制格式的延迟为80 ns,可以随机访问,并且可以在进程之间共享.这只能很快地工作,因为它不会在每条记录上将数据提交到磁盘,但您可以测试,如果JVM在任何时候崩溃,则不会丢失写入编年史的数据.

  • 如果数据必须提交到磁盘,那么您需要同步系统调用:http://linux.die.net/man/2/sync (2认同)
  • 从OS/X fsync(2)[手册页](https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/fsync.2.html):"对于需要的应用程序更严格保证数据的完整性,Mac OS X提供F_FULLFSYNC fcntl.F_FULLFSYNC fcntl要求驱动器将所有缓冲数据刷新到永久存储器.需要严格写入顺序的应用程序(如数据库)应使用F_FULLF-SYNC确保他们的数据按照他们期望的顺序编写.有关更多详细信息,请参阅fcntl(2)." (2认同)

Dav*_*eri 0

Java 中 fputs 的等价物是file.write("012345678901234567890123456789");,你正在调用 4 个函数,而在 C 中只调用 1 个函数,延迟似乎很明显