8

我试图找出为什么 OkHttp 使用 Okio 而不是 BufferedInputStream 和 BufferedOutputStream 来缓冲数据。我使用以下代码进行验证:</p>

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 效率更高。我的验证有什么问题吗?

4

2 回答 2

8

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

我在 Okio 基准测试中去掉了额外的间接性,从 aSource而不是middle 开始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。如果你想试试,我对结果很感兴趣!

于 2017-07-04T23:30:06.223 回答
-1

我改变了你的代码

Source bufferSource = Okio.buffer(Okio.source(inputStream));

Source bufferSource = null;
try {
      bufferSource = Okio.buffer(Okio.source(targetFile));
} catch (Exception e) {
      e.printStackTrace();
}

它看起来比以前快得多,但我不知道为什么。okio的源码查查需要时间。

于 2017-09-14T05:59:35.230 回答