【问题标题】:Why am I writing data to a file in java so slow为什么我在java中将数据写入文件这么慢
【发布时间】:2017-07-10 12:35:42
【问题描述】:

我正在使用java.nio.channels.FileChannel 将数据写入文件。这是我的代码:

RandomAccessFile raf = new RandomAccessFile(file, "rws");
FileChannel fileChannel = raf.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(4096);
long offset = 0;
while (offset < 1024 * 1024 * 1024) {
    buffer.clear();
    fileChannel.write(buffer, offset);
    buffer.clear();
    offset += buffer.remaining();
    logger.warn("fake write {} {}", offset, buffer.remaining());
}

我的输出是这样的:

WARN [11:01:58,498][writer]BackUp(151):fake write 3047424 4096
WARN [11:01:58,507][writer]BackUp(151):fake write 3051520 4096
WARN [11:01:58,515][writer]BackUp(151):fake write 3055616 4096
WARN [11:01:58,523][writer]BackUp(151):fake write 3059712 4096
WARN [11:01:58,532][writer]BackUp(151):fake write 3063808 4096
WARN [11:01:58,540][writer]BackUp(151):fake write 3067904 4096
WARN [11:01:58,549][writer]BackUp(151):fake write 3072000 4096
WARN [11:01:58,557][writer]BackUp(151):fake write 3076096 4096
WARN [11:01:58,565][writer]BackUp(151):fake write 3080192 4096
WARN [11:01:58,574][writer]BackUp(151):fake write 3084288 4096
WARN [11:01:58,582][writer]BackUp(151):fake write 3088384 4096
WARN [11:01:58,590][writer]BackUp(151):fake write 3092480 4096
WARN [11:01:58,599][writer]BackUp(151):fake write 3096576 4096
WARN [11:01:58,607][writer]BackUp(151):fake write 3100672 4096
WARN [11:01:58,615][writer]BackUp(151):fake write 3104768 4096
WARN [11:01:58,624][writer]BackUp(151):fake write 3108864 4096
WARN [11:01:58,632][writer]BackUp(151):fake write 3112960 4096

你可以看到我是按顺序写的,但是每 4K 花费 8ms,即 500 KB/s。这很慢,我对此感到非常困惑。

【问题讨论】:

  • 如果这是一个真正的(旋转的)磁盘,在模式 s 下,您几乎强制每次写入都等待磁盘转一圈,而消费类磁盘的速度很少超过 7200rpm = 8.333 毫秒/转。
  • 就是这样!非常感谢。

标签: java file io nio


【解决方案1】:
  1. 我会使用write(buffer) 并忘记offset 参数,因为它可能会导致搜索,这会使系统调用的数量增加一倍。上次我测量它时(很久以前),搜索效率低得惊人,甚至搜索到你已经在的地方,就像在这种情况下一样。

  2. 如果您甚至将缓冲区大小增加一倍,您可能会将总时间减半。 4096 大约是我将用于任何事情的最小缓冲区大小。例如,BufferedOutputStream 使用 8192,对于备份程序,我会使用更大的值。

  3. 但是,如果您真的只是想写入一兆字节的零,只需将RandomAccessFile 扩展为setLength()。无需写入。

【讨论】:

  • 这只是一个测试演示,我的真实程序类似于文件系统,会处理大量的序列或无序列IO。
  • 我也试过用write(buffer),结果都一样。但是如果我把缓冲区大小设为1M,速度会快很多。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-13
  • 1970-01-01
  • 2010-11-26
  • 1970-01-01
  • 1970-01-01
  • 2012-04-30
相关资源
最近更新 更多