I tried to find out why OkHttp uses Okio but not BufferedInputStream and BufferedOutputStream to buffer data. I used following code to verify:
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();
}
I called bufferedIO() 5 times, the results are:
357ms
299ms
311ms
324ms
331ms
I called okio() 5 times, the results are:
524ms
661ms
555ms
525ms
573ms
According to the results, BufferedInputStream and BufferedOutputStream are more efficient than Okio. Is there anything wrong with my verification?
Okio is a library that complements java.io and java. nio to make it much easier to access, store, and process your data. It started as a component of OkHttp, the capable HTTP client included in Android. It's well-exercised and ready to solve new problems.
I ran this benchmark on my desktop and my results were very inconsistent. I think the benchmark is ultimately measuring filesystem performance more than the I/O library.
I took out the extra indirection in the Okio benchmark, starting with a Source
rather than the intermediate FileInputStream
. I also removed the page-by-page loop which isn’t necessary for Okio: you can just call writeAll()
to copy an entire source to a sink:
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");
}
}
My results were wildly inconsistent due to file system performance - individual runs varied by more than 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
Overall Okio was more efficient here, but that might just be luck. A better benchmark would isolate the unreliable filesystem I/O. If you’d like to try that, I’m interested in the results!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With