android – 为什么Okio比BufferedInputStream和BufferedOutputStream更有效?

我试图找出为什么OkHttp使用Okio而不是BufferedInputStream和BufferedOutputStream来缓冲数据.
我使用以下代码来验证:

private String targetPath = Environment.getExternalStorageDirectory()
        + File.separator + "performance.dat";

private InputStream getInputStream() {
    try {
        File targetFile = new File(targetPath);

        if (targetFile.exists()) {
            targetFile.delete();
        }

        targetFile.createNewFile();
        return new FileInputStream("/sdcard/file.zip");
    } catch (IOException e) {
        e.printStackTrace();
    }

    return null;
}

public void bufferedIO(View view) {
    new Thread() {

        @Override
        public void run() {
            InputStream inputStream = getInputStream();

            if (inputStream == null) {
                return;
            }

            long start = System.currentTimeMillis();

            inputStream = new BufferedInputStream(inputStream, 8192);
            File targetFile = new File(targetPath);
            BufferedOutputStream fileOutputStream = null;

            try {
                fileOutputStream = new BufferedOutputStream(new FileOutputStream(targetFile, true), 8192);
                byte[] buffer = new byte[4096];

                int count;
                while ((count = inputStream.read(buffer)) > 0) {
                    fileOutputStream.write(buffer, 0, count);
                }

                fileOutputStream.flush();
                Log.i("performance", "BufferedInputStream and BufferedOutputStream: " + (System.currentTimeMillis() - start) + "ms");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                if (fileOutputStream != null) {
                    try {
                        fileOutputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }.start();
}

public void okio(View view) {
    new Thread() {

        @Override
        public void run() {
            InputStream inputStream = getInputStream();

            if (inputStream == null) {
                return;
            }

            long start = System.currentTimeMillis();

            File targetFile = new File(targetPath);
            Source bufferSource = Okio.buffer(Okio.source(inputStream));
            BufferedSink bufferSink = null;

            try {
                bufferSink = Okio.buffer(Okio.sink(targetFile));

                while ((bufferSource.read(bufferSink.buffer(), 4096)) != -1) {
                    bufferSink.emitCompleteSegments();
                }
                bufferSink.flush();

                Log.i("performance", "okio: " + (System.currentTimeMillis() - start) + "ms");
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    bufferSource.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                if (bufferSink != null) {
                    try {
                        bufferSink.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }.start();
}

我调用了bufferedIO()5次,结果如下:

357ms
299ms
311ms
324ms
331ms

我打了okio()5次,结果是:

524ms
661ms
555ms
525ms
573ms

根据结果​​,BufferedInputStream和BufferedOutputStream比Okio更有效.我的验证有什么问题吗?

解决方法:

我在桌面上运行此基准测试,结果非常不一致.我认为基准测试最终是测量文件系统性能而不是I / O库.

我在Okio基准测试中取出了额外的间接,从Source而不是中间FileInputStream开始.我还删除了Okio不需要的逐页循环:您可以调用writeAll()将整个源复制到接收器:

public void okio() throws IOException {
  long start = System.currentTimeMillis();

  File targetFile = new File(targetPath);
  targetFile.delete();

  try (BufferedSink sink = Okio.buffer(Okio.sink(targetFile));
      Source bufferSource = Okio.source(new File(sourcePath))) {
    sink.writeAll(bufferSource);
    System.out.println("okio: " + (System.currentTimeMillis() - start) + "ms");
  }
}

由于文件系统性能,我的结果非常不一致 – 个别运行的变化超过200%.

okio:  67ms   java.io: 106ms
okio:  98ms   java.io: 106ms
okio: 108ms   java.io: 110ms
okio: 121ms   java.io: 113ms
okio: 125ms   java.io: 116ms
okio: 131ms   java.io: 118ms
okio: 143ms   java.io: 143ms
okio: 154ms   java.io: 145ms
okio: 191ms   java.io: 146ms
okio: 217ms   java.io: 239ms

整体Okio在这里效率更高,但这可能只是运气.更好的基准测试将隔离不可靠的文件系统I / O.如果您想尝试一下,我对结果感兴趣!

上一篇:JAVA锁的膨胀过程和优化


下一篇:Okio原理分析之字符编码