Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Java磁盘I/O的执行速度比用C编写的等效I/O代码慢得多?_Java_Performance_Io_Java 8_Solid State Drive - Fatal编程技术网

为什么Java磁盘I/O的执行速度比用C编写的等效I/O代码慢得多?

为什么Java磁盘I/O的执行速度比用C编写的等效I/O代码慢得多?,java,performance,io,java-8,solid-state-drive,Java,Performance,Io,Java 8,Solid State Drive,我有一个SSD磁盘,每个规格的IOPS应不低于10k。我的基准测试证实它可以提供20k IOPS 然后我创建了这样一个测试: private static final int sector = 4*1024; private static byte[] buf = new byte[sector]; private static int duration = 10; // seconds to run private static long[] timings = new long[50000]

我有一个SSD磁盘,每个规格的IOPS应不低于10k。我的基准测试证实它可以提供20k IOPS

然后我创建了这样一个测试:

private static final int sector = 4*1024;
private static byte[] buf = new byte[sector];
private static int duration = 10; // seconds to run
private static long[] timings = new long[50000];
public static final void main(String[] args) throws IOException {
    String filename = args[0];
    long size = Long.parseLong(args[1]);
    RandomAccessFile raf = new RandomAccessFile(filename, "r");
    Random rnd = new Random();
    long start = System.currentTimeMillis();
    int ios = 0;
    while (System.currentTimeMillis()-start<duration*1000) {
        long t1 = System.currentTimeMillis();
        long pos = (long)(rnd.nextDouble()*(size>>12));
        raf.seek(pos<<12);
        int count = raf.read(buf);
        timings[ios] = System.currentTimeMillis() - t1;
        ++ios;
    }
    System.out.println("Measured IOPS: " + ios/duration);
    int totalBytes = ios*sector;
    double totalSeconds = (System.currentTimeMillis()-start)/1000.0;
    double speed = totalBytes/totalSeconds/1024/1024;
    System.out.println(totalBytes+" bytes transferred in "+totalSeconds+" secs ("+speed+" MiB/sec)");
    raf.close();
    Arrays.sort(timings);
    int l = timings.length;
    System.out.println("The longest IO = " + timings[l-1]);
    System.out.println("Median duration = " + timings[l-(ios/2)]);
    System.out.println("75% duration = " + timings[l-(ios * 3 / 4)]);
    System.out.println("90% duration = " + timings[l-(ios * 9 / 10)]);
    System.out.println("95% duration = " + timings[l-(ios * 19 / 20)]);
    System.out.println("99% duration = " + timings[l-(ios * 99 / 100)]);
}
为什么它比C中的相同测试慢得多

更新:以下是提供20k IOPS的Python代码:

def iops(dev, blocksize=4096, t=10):

    fh = open(dev, 'r')
    count = 0
    start = time.time()
    while time.time() < start+t:
        count += 1
        pos = random.randint(0, mediasize(dev) - blocksize) # need at least one block left
        pos &= ~(blocksize-1)   # sector alignment at blocksize
        fh.seek(pos)
        blockdata = fh.read(blocksize)
    end = time.time()
    t = end - start
    fh.close()

因为您使用的是
RandomAccessFile
,这是Java中磁盘I/O速度最慢的方法之一

尝试使用更快的工具,如
缓冲输出流
缓冲输出流
,看看你的速度如何

如果您想知道为什么这会对SSD产生影响(因为SSD应该擅长随机访问),那么这与访问的随机性无关;这是关于带宽的问题。如果您的SSD具有1024位宽的总线,但每次写入时仅写入64位(就像写入
long
s或
double
s那样),则速度会变慢。(当然,这些数字只是为了举例。)


现在,我可以看出,这不是您的代码正在做的(或者至少看起来是这样),但很可能
RandomAccessFile
就是这样在后台实现的。再次尝试使用缓冲流,看看会发生什么。

从本文中可以看出,旧式java随机访问速度要慢2.5到3.5倍。这是一个研究pdf,所以不要因为你点击它而责怪我

链接:

Java原始I/O比C/C++慢,因为Java中的系统调用是 更昂贵;因此,缓冲提高了Java I/O性能 减少了系统调用,但对于较大的缓冲区大小并没有很大的好处; 直接缓冲优于Java提供的缓冲I/O 类,因为用户可以根据自己的需要进行定制;增加的 操作大小有助于提高I/O性能,而不会产生开销;和系统 在Java本机方法中,调用是廉价的,而调用 本地方法相当高。当本机呼叫数为 适当降低,可以实现与C/C++相当的性能

从那个时代开始就是你的代码。现在我们不使用
RandomAccessFile
而是使用
java.nio
重写它,好吗


我有一些nio2代码可以用来对抗C。垃圾收集可以被排除:)

你的问题是基于一个错误的假设,即类似于Java代码的C代码可以像IOMeter一样执行。因为这个假设是错误的,所以C性能和Java性能之间并没有差异可以解释

如果您的问题是为什么Java代码相对于IOMeter的性能如此糟糕,那么答案是IOMeter不像您的代码那样一次发出一个请求。要从SSD获得充分的性能,您需要保持其请求队列为非空,并且在发出下一个请求之前等待每次读取完成不可能做到这一点


尝试使用线程池来发出请求。

RandomAccess在Java中速度最快,但无法与C相比。
但是,如果您想更好地比较JVM上的IO性能,请阅读Martin Thompson关于这个主题的优秀博客:

您在Java和C中使用的是相同的随机数序列吗?请注意,原始磁盘传输速度与此无关。对于随机访问,您需要查看查找时间。为什么将40000.java文件写入我的pocket usb驱动器需要8分钟。与我在20秒内(相同的累计大小)完成的1 mp4相比?我想拿回我的钱(用于U盘)把同一个测试的代码用C写出来,这样读者就可以确定被比较的是什么。我怀疑你不是在以貌取人。除非显式使用缓冲,否则不会缓冲Java IO。默认情况下,标准的C API缓冲区,除非您使用低级API。你的C代码是什么样子的?有趣的是,这个类名为NioTest,但不包含NIO代码。虽然有大量证据表明使用NIO并不能保证速度的提高,但我仍然希望看到使用FileChannel进行相同的测试,甚至可以使用MappedByteBuffer,因为这个问题声称Java本身存在缺陷。
BufferedInputStream
什么时候需要2 TB的内存?你知道BufferedInputStream是用于顺序读取(而我的测试是用于随机读取)的吗?这个答案根本不是关于我的问题。@Antonio你问了一个问题,所以任何人都可以免费帮助你。如果你不同意一个答案/认为它是错误的,就否决它,继续前进。不要要求某人删除答案。另外,请不要粗鲁/好斗(在评论或问题标题中)。@Antonio-有答案并不妨碍你得到另一个答案。对回答你的人粗鲁无礼。请理解RedRoboHood自愿花时间来帮助你。我相信我做错了什么。我就是不知道怎么了。我试过NIO,但眼压都一样。如果你能提出替代代码,我将不胜感激。它不会更快,但也不会慢3.5倍。我过去只做汇编和C,所以我不会妄想。好吧,基本上不是。不熟练的文章。非常肮脏的误导结果。我在问问题之前读了它。
def iops(dev, blocksize=4096, t=10):

    fh = open(dev, 'r')
    count = 0
    start = time.time()
    while time.time() < start+t:
        count += 1
        pos = random.randint(0, mediasize(dev) - blocksize) # need at least one block left
        pos &= ~(blocksize-1)   # sector alignment at blocksize
        fh.seek(pos)
        blockdata = fh.read(blocksize)
    end = time.time()
    t = end - start
    fh.close()
...
RandomAccessFile raf = new RandomAccessFile(filename, "r");
InputStream in = Channels.newInputStream(raf.getChannel());
...
int count = in.read(buf);
...