我试图找出为什么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.如果您想尝试一下,我对结果感兴趣!