简体   繁体   English

自动选择文件I / O的缓冲区大小

[英]Automatically selecting buffer size for File I/O

I have a pretty basic doubt. 我有一个非常基本的怀疑。 Often, I have to write apps which use buffered file I/O and every time I am faced with the dilemma of choosing the buffer size and I end up doing trial and error often with pretty nasty results. 通常,我必须编写使用缓冲文件I / O的应用程序,并且每当我面临选择缓冲区大小的困境时,我最终会通过非常讨厌的结果进行反复试验。 I want to know if there is any method or algorithm which can automatically determine the optimum buffer size for the job based on the underlying platform like Teracopy does when handling files in Windows. 我想知道是否有任何方法或算法可以根据Teracopy在Windows中处理文件时所基于的底层平台自动确定作业的最佳缓冲区大小。 I mainly use Qt for the GUI. 我主要使用Qt作为GUI。

If possible a tiny example in C/C++/C#/Java is very much appreciated! 如果可能的话,非常感谢C / C ++ / C#/ Java中的一个小例子!

Thanks! 谢谢!

In Java the optimal is usually around the L1 cache size which is typically 32 KB. 在Java中,最佳值通常在L1高速缓存大小附近,通常为32 KB。 In Java, at least choosing 1024 bytes or 1 MB doesn't make much difference (<20%) 在Java中,至少选择1024字节或1 MB并没有太大区别(<20%)

If you are reading data sequentially, usually your OS is smart enough to detect this and prefetch the data for you. 如果您按顺序读取数据,通常您的操作系统足够智能,可以检测到这些并为您预取数据。

What you can do is the following. 你能做的是以下几点。 This test appears to show a significant difference in the block sizes used. 该测试似乎显示使用的块大小的显着差异。

public static void main(String... args) throws IOException {
    for (int i = 512; i <= 2 * 1024 * 1024; i *= 2)
        readWrite(i);
}

private static void readWrite(int blockSize) throws IOException {
    ByteBuffer bb = ByteBuffer.allocateDirect(blockSize);
    long start = System.nanoTime();
    FileChannel out = new FileOutputStream("deleteme.dat").getChannel();
    for (int i = 0; i < (1024 << 20); i += blockSize) {
        bb.clear();
        while (bb.remaining() > 0)
            if (out.write(bb) < 1) throw new AssertionError();
    }
    out.close();
    long mid = System.nanoTime();
    FileChannel in = new FileInputStream("deleteme.dat").getChannel();
    for (int i = 0; i < (1024 << 20); i += blockSize) {
        bb.clear();
        while (bb.remaining() > 0)
            if (in.read(bb) < 1) throw new AssertionError();
    }
    in.close();
    long end = System.nanoTime();
    System.out.printf("With %.1f KB block size write speed %.1f MB/s, read speed %.1f MB/s%n",
            blockSize / 1024.0, 1024 * 1e9 / (mid - start), 1024 * 1e9 / (end - mid));
}

prints 版画

With 0.5 KB block size write speed 96.6 MB/s, read speed 169.7 MB/s
With 1.0 KB block size write speed 154.2 MB/s, read speed 312.2 MB/s
With 2.0 KB block size write speed 201.5 MB/s, read speed 438.7 MB/s
With 4.0 KB block size write speed 288.0 MB/s, read speed 733.9 MB/s
With 8.0 KB block size write speed 318.4 MB/s, read speed 711.8 MB/s
With 16.0 KB block size write speed 540.6 MB/s, read speed 1263.7 MB/s
With 32.0 KB block size write speed 726.0 MB/s, read speed 1370.9 MB/s
With 64.0 KB block size write speed 801.8 MB/s, read speed 1536.5 MB/s
With 128.0 KB block size write speed 857.5 MB/s, read speed 1539.6 MB/s
With 256.0 KB block size write speed 794.0 MB/s, read speed 1781.0 MB/s
With 512.0 KB block size write speed 676.2 MB/s, read speed 1221.4 MB/s
With 1024.0 KB block size write speed 886.3 MB/s, read speed 1501.5 MB/s
With 2048.0 KB block size write speed 784.7 MB/s, read speed 1544.9 MB/s

What this test doesn't show is that the hard drive only supports 60 MB/s reads and 40 MB/s writes. 此测试未显示的是硬盘驱动器仅支持60 MB / s读取和40 MB / s写入。 All you are testing is the speed in and out of cache. 您正在测试的是缓存内外的速度。 If this was your only priority, you would use a memory mapped file. 如果这是您唯一的优先级,您将使用内存映射文件。

int blockSize = 32 * 1024;
ByteBuffer bb = ByteBuffer.allocateDirect(blockSize);
FileChannel out = new FileOutputStream("deleteme.dat").getChannel();
for (int i = 0; i < (1024 << 20); i += blockSize) {
    bb.clear();
    while (bb.remaining() > 0)
        if (out.write(bb) < 1) throw new AssertionError();
}
out.close();

long start = System.nanoTime();
FileChannel in = new FileInputStream("deleteme.dat").getChannel();
MappedByteBuffer map = in.map(FileChannel.MapMode.READ_ONLY, 0, in.size());
in.close();
long end = System.nanoTime();
System.out.printf("Mapped file at a rate of %.1f MB/s%n",
        1024 * 1e9 / (end - start));

prints 版画

Mapped file at a rate of 589885.5 MB/s

This is so fast because it just maps the data in the OS disk cache directly into the memory of the application (so no copying is required) 这是如此之快,因为它只是将OS磁盘缓存中的数据直接映射到应用程序的内存中(因此不需要复制)

I have see this code in C: 我在C中看到了这段代码:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
  struct stat fi;
  stat("/", &fi);
  printf("%d\n", fi.st_blksize);
  return 0;
}

It return the optimal block size. 它返回最佳块大小。 You need use it to do that's. 你需要用它来做那件事。 I use stream source to destination with 16*block size to have optimal performance. 我使用流源到16 *块大小的目标,以获得最佳性能。 Because this test will reveal the best with a pc at idle with some hardware/OS. 因为这个测试将通过一些硬件/操作系统在空闲时显示出最佳效果。 But not real case. 但不是真实的情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM