Skip to content

Instantly share code, notes, and snippets.

@tyru
Last active August 29, 2015 14:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tyru/204f22473ecc6448706b to your computer and use it in GitHub Desktop.
Save tyru/204f22473ecc6448706b to your computer and use it in GitHub Desktop.
『Re: InputStreamからStringへの変換』の記事のコードはNIO使えばもっと速くなるんじゃないかと思ってベンチマーク取ってみた
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
public class BenchmarkMain {
private static final int BUFFER_SIZE = 1024;
private static final Charset UTF16 = Charset.forName("UTF-16");
public static final String TEST_FILE_NAME = "test.txt";
public static final boolean PRINT_EACH_RESULT = false;
private static final int COUNT = 100;
private static final int MEDIAN_SAMPLE_NUM = 30;
private static final TimeUnit RESULT_TIME_UNIT = TimeUnit.NANOSECONDS;
public static void main(String[] args) {
Task t1 = new Task("convertInputStreamToString()") {
public void run() throws Exception {
convertInputStreamToString(this.is);
}
};
Task t2 = new Task("convertInputStreamToStringWithCharset()") {
public void run() throws Exception {
convertInputStreamToStringWithCharset(this.is, UTF16);
}
};
Task t3 = new Task("convertInputStreamToStringNio()") {
public void run() throws Exception {
convertInputStreamToStringNio(is);
}
};
Task t4 = new Task("convertInputStreamToStringNioWithCharset()") {
public void run() throws Exception {
convertInputStreamToStringNioWithCharset(is, UTF16);
}
};
Task t5 = new Task("convertInputStreamToStringNioDirectBuffer()") {
public void run() throws Exception {
convertInputStreamToStringNioDirectBuffer(is);
}
};
Task t6 = new Task("convertInputStreamToStringNioDirectBufferWithCharset()") {
public void run() throws Exception {
convertInputStreamToStringNioDirectBufferWithCharset(is, UTF16);
}
};
try {
Task[] tasks = { t1, t2, t3, t4, t5, t6 };
// Task[] tasks = { t1, t2, t3, t4 };
for (Task task : tasks) {
task.start();
}
System.out.println("Result:");
for (Task task : tasks) {
task.printResult();
}
System.out.println();
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
static abstract class Task {
private final String taskName;
protected InputStream is;
private long[] resultTimes = new long[COUNT];
public Task(String taskName) {
this.taskName = taskName;
}
abstract public void run() throws Exception;
public void start() throws Exception {
this.is = getTestInputStream();
for (int i = 0; i < COUNT; i++) {
long start = System.nanoTime();
this.run();
long end = System.nanoTime();
this.resultTimes[i] = end - start;
}
}
public void printResult() {
Arrays.sort(this.resultTimes);
if (PRINT_EACH_RESULT) {
for (int i = 0; i < resultTimes.length; i++) {
long resultTime = this.resultTimes[i];
System.out.println(" " + this.taskName + " : "
+ RESULT_TIME_UNIT.convert(resultTime, TimeUnit.NANOSECONDS)
+ " " + RESULT_TIME_UNIT.name().toLowerCase());
}
}
long resultTime = calcMedian();
System.out.printf(" %s (median %d/%d) : %d %s\n",
this.taskName,
MEDIAN_SAMPLE_NUM,
COUNT,
RESULT_TIME_UNIT.convert(resultTime, TimeUnit.NANOSECONDS),
RESULT_TIME_UNIT.name().toLowerCase());
}
private long calcMedian() {
assert COUNT >= MEDIAN_SAMPLE_NUM;
// this.resultTimes must bo sorted.
// Arrays.sort(this.resultTimes);
BigDecimal sum = new BigDecimal(0);
// [begin, end)
int begin = (this.resultTimes.length - MEDIAN_SAMPLE_NUM) / 2;
int end = begin + MEDIAN_SAMPLE_NUM;
for (int i = begin; i < end; i++) {
sum = sum.add(new BigDecimal(this.resultTimes[i]));
}
return sum.divide(new BigDecimal(MEDIAN_SAMPLE_NUM), 0, RoundingMode.HALF_UP).longValueExact();
}
}
private static InputStream getTestInputStream() throws FileNotFoundException {
return new FileInputStream("test.txt");
}
/**
* thincaさんが教えてくれたコード
* @param is
* @return String
* @throws IOException
*/
static String convertInputStreamToString(InputStream is) throws IOException {
InputStreamReader reader = new InputStreamReader(is);
StringBuilder builder = new StringBuilder();
char[] buf = new char[BUFFER_SIZE];
int numRead;
while (0 <= (numRead = reader.read(buf))) {
builder.append(buf, 0, numRead);
}
return builder.toString();
}
/**
* thincaさんが教えてくれたコードをCharset指定できるようにしたメソッド
* @param is
* @return String
* @throws IOException
*/
static String convertInputStreamToStringWithCharset(InputStream is, Charset charset) throws IOException {
InputStreamReader reader = new InputStreamReader(is, charset);
StringBuilder builder = new StringBuilder();
char[] buf = new char[BUFFER_SIZE];
int numRead;
while (0 <= (numRead = reader.read(buf))) {
builder.append(buf, 0, numRead);
}
return builder.toString();
}
/**
* NIO使うようにしたメソッド(`allocate()`版)
* @param is
* @return String
* @throws IOException
*/
static String convertInputStreamToStringNio(InputStream is) throws IOException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
ReadableByteChannel channel = Channels.newChannel(is);
ByteBuffer buf = ByteBuffer.allocate(BUFFER_SIZE);
buf.mark();
int numRead;
while (0 <= (numRead = channel.read(buf))) {
result.write(buf.array(), 0, numRead);
buf.reset();
}
return result.toString();
}
/**
* NIO使うようにしたメソッド(`allocate()`版)をCharset指定できるようにしたメソッド
* @param is
* @param charset
* @return String
* @throws IOException
*/
static String convertInputStreamToStringNioWithCharset(InputStream is, Charset charset) throws IOException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
ReadableByteChannel channel = Channels.newChannel(is);
ByteBuffer buf = ByteBuffer.allocate(BUFFER_SIZE);
buf.mark();
int numRead;
while (0 <= (numRead = channel.read(buf))) {
result.write(buf.array(), 0, numRead);
buf.reset();
}
return result.toString(charset.name());
}
/**
* NIO使うようにしたメソッド(`allocateDirect()`版)
* @param is
* @return String
* @throws IOException
*/
static String convertInputStreamToStringNioDirectBuffer(InputStream is) throws IOException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
ReadableByteChannel channel = Channels.newChannel(is);
ByteBuffer buf = ByteBuffer.allocateDirect(BUFFER_SIZE);
buf.mark();
byte[] rawBuf = new byte[BUFFER_SIZE];
int numRead;
while (0 <= (numRead = channel.read(buf))) {
buf.reset();
buf.get(rawBuf, 0, numRead);
result.write(rawBuf, 0, numRead);
buf.reset();
}
return result.toString();
}
/**
* NIO使うようにしたメソッド(`allocateDirect()`版)をCharset指定できるようにしたメソッド
* @param is
* @param charset
* @return String
* @throws IOException
*/
static String convertInputStreamToStringNioDirectBufferWithCharset(InputStream is, Charset charset) throws IOException {
ByteArrayOutputStream result = new ByteArrayOutputStream();
ReadableByteChannel channel = Channels.newChannel(is);
ByteBuffer buf = ByteBuffer.allocateDirect(BUFFER_SIZE);
buf.mark();
byte[] rawBuf = new byte[BUFFER_SIZE];
int numRead;
while (0 <= (numRead = channel.read(buf))) {
buf.reset();
buf.get(rawBuf, 0, numRead);
result.write(rawBuf, 0, numRead);
buf.reset();
}
return result.toString(charset.name());
}
}
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
public class CreateTestFile {
// Please modify the following constants.
// private static final int BUFFER_SIZE = 128 * 1024 * 1024; /* 128MiB */
// private static final int FILE_SIZE = 1024 * 1024 * 1024; /* 1GiB */
private static final int BUFFER_SIZE = 8 * 1024 * 1024; /* 8MiB */
private static final int FILE_SIZE = 32 * 1024 * 1024; /* 32MiB */
public static void main(String[] args) {
// Create test data.
byte[] buf = new byte[BUFFER_SIZE];
for (int i = 0; i < buf.length; i++) {
buf[i] = '0'; // file is filled with character '0'
}
// Delete test file if it exists.
try {
Files.deleteIfExists(Paths.get(BenchmarkMain.TEST_FILE_NAME));
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
final int loopWriteNum = FILE_SIZE / BUFFER_SIZE;
final int lastWriteNum = FILE_SIZE % BUFFER_SIZE;
final boolean append = true;
try (FileOutputStream out = new FileOutputStream(BenchmarkMain.TEST_FILE_NAME, append)) {
for (int i = 0; i < loopWriteNum; i++) {
out.write(buf);
System.out.printf("Written %d/%d byte(s).\n", (i + 1) * BUFFER_SIZE, FILE_SIZE);
}
if (lastWriteNum > 0) {
out.write(buf, 0, lastWriteNum);
System.out.printf("Written %d/%d byte(s).\n", FILE_SIZE, FILE_SIZE);
}
System.out.println("Done.");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment