Java 7的nio.file包在创建新文件时非常慢

Dav*_*rks 6 java file-io java-7 nio2

我正在尝试从java程序创建300M文件,我从旧的文件API切换到新的java 7 nio包,但是新的包比旧的更慢.

我看到的CPU利用率低于使用旧文件API时的CPU利用率,但我正在运行这个简单的代码,我得到0.5Mbytes/sec的文件传输速率,而java的写入正在读取一个磁盘并写入另一个(写入是访问磁盘的唯一进程).

Files.write(FileSystems.getDefault().getPath(filePath), fiveToTenKBytes, StandardOpenOption.CREATE);
Run Code Online (Sandbox Code Playgroud)

有没有希望在这里获得合理的吞吐量?


更新:

我正在从大文件中解包3亿个5-10k字节的图像文件.我有3个磁盘,1个本地磁盘和2个SAN连接(大型文件的典型吞吐率约为20MB /秒).

我也尝试过这段代码,它将速度提高到不到2MB /秒的吞吐量(解压缩这些文件需要9天).

ByteBuffer byteBuffer = ByteBuffer.wrap(imageBinary, 0, (BytesWritable)value).getLength());
FileOutputStream fos = new FileOutputStream( imageFile );
fos.getChannel().write(byteBuffer);
fos.close();
Run Code Online (Sandbox Code Playgroud)

我从本地磁盘读取并写入SAN连接磁盘.我正在阅读Hadoop SequenceFile格式,hadoop通常能够使用基本相同的代码以20MB /秒的速度读取这些文件.

除了超级缓慢之外,唯一看起来不合适的是,我看到更多的读取IO比写入IO大约2:1,尽管序列文件是gziped(图像实际上比例为1:1),所以压缩文件应该是约.输出1:1.


第二次更新

看着iostat我看到一些奇怪的数字,我们在这里看xvdf,我有一个java进程读取xvdb和写入xvdf并且没有活动的ohter进程xvdf

iostat -d 30
Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
xvdap1            1.37         5.60         4.13        168        124
xvdb             14.80       620.00         0.00      18600          0
xvdap3            0.00         0.00         0.00          0          0
xvdf            668.50      2638.40       282.27      79152       8468
xvdg           1052.70      3751.87      2315.47     112556      69464
Run Code Online (Sandbox Code Playgroud)

读取xvdf是写入的10倍,这是令人难以置信的.

fstab
/dev/xvdf       /mnt/ebs1       auto    defaults,noatime,nodiratime     0       0
/dev/xvdg       /mnt/ebs2       auto    defaults,noatime,nodiratime     0       0
Run Code Online (Sandbox Code Playgroud)

par*_*fal 1

我认为你的缓慢是来自创建新文件,而不是实际传输。我相信在Linux中创建文件是一个同步操作:系统调用在文件创建和目录更新之前不会返回。这建议您可以做几件事:

  • 将多个写入器线程与单个读取器线程结合使用。读取器线程会将数据从源文件读取到 a 中byte[],然后创建一个Runnable从此数组写入输出文件的文件。使用具有大量线程(可能是 100 个或更多)的线程池,因为它们将花费大部分时间等待完成creat。根据您拥有的内存量设置此池的入站队列的容量:如果您的文件大小为 10k,那么队列容量 1,000 似乎是合理的(没有充分的理由允许读者比编写者走得太远) ,因此您甚至可以使用两倍线程数的容量)。
  • BufferedInputStream使用 basic s 和,而不是 NIO BufferedOutputStreams。这里的问题是系统调用,而不是内存速度(NIO 类旨在防止堆内存和堆外内存之间的复制)。

我假设您已经知道不要尝试将所有文​​件存储到单个目录中。甚至在一个目录中存储数百个以上的文件。

作为另一种选择,您是否考虑过使用 S3 进行存储?我猜测它的存储桶键比实际目录更有效,并且有一个文件系统可以让您像访问文件一样访问存储桶(我自己还没有尝试过)。