BOJ JAVA ํ์ด์์ ์ BufferedReader, BufferedWriter ๋ฅผ ์ฌ์ฉํ ๊น?
์ฌ๋๋ค์ PS ์ค ์๊ฐ ํจ์จ์ ์กฐ๊ธ์ด๋ผ๋ ์ฌ๋ฆฌ๊ธฐ ์ํด์ Fast I/O๋ฅผ ์ฌ์ฉํ๋ค.
๋ณดํต I/O ์๋๋ Default I/O, Fast I/O, Custom Fast I/O ๊ฐ ์๋ค.
์ฐ ๊ณ ์๋ค์ ์ข ์ข Custom Fast I/O๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋ณผ ์ ์๋๋ฐ ๋๋ ๊ธฐ๋ณธ์ ์ธ Fast I/O๋ง ์ฌ์ฉํ๋ค. (์ด๋ณด)
Python ์์๋ sys.stdin.readline, C++ ์์๋ ios_base::sync_with_stdio(0), C์์๋ fread() ๋ฑ
Java์์๋ BufferedReader ๋ BufferedWriter๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
๊ทธ๋ผ ์ ์ฌ์ฉํ๋์ง ํ ๋ฒ ์์๋ณด์.
BufferedReader vs Scanner
BufferedReader
public class BufferedReader extends Reader {
private Reader in;
private char[] cb;
private static final int DEFAULT_CHAR_BUFFER_SIZE = 8192;
public BufferedReader(Reader in, int sz) {
super(in);
if (sz <= 0)
throw new IllegalArgumentException("Buffer size <= 0");
this.in = in;
cb = new char[sz];
nextChar = nChars = 0;
}
public BufferedReader(Reader in) {
this(in, DEFAULT_CHAR_BUFFER_SIZE);
}
}
์๋ฐ์์ ๊ตฌํํ๋ BufferedReader Class ์ ๋ณด๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก 8Byte์ char ์๋ฃํ์ ์ ์ฅํ ์ ์๋ Buffer๋ฅผ ๊ฐ์ง๊ณ ์๊ณ ์์ฑ๊ฐ์ ๋ฐ๋ผ ๋ ๋๋ฆด ์๋ ์๋ค.
ํ ๋ฒ์ 8Byte์ ๋ฌธ์๋ฅผ read ํ ์ ์๋ค๊ณ ๋ณด๋ฉด ๋๋ค.
Scanner
public final class Scanner implements Iterator<String>, Closeable {
private CharBuffer buf;
private static final int BUFFER_SIZE = 1024;
private int position;
private Matcher matcher;
private Pattern delimPattern;
private Pattern hasNextPattern;
private int hasNextPosition;
private String hasNextResult;
private Readable source;
private boolean sourceClosed = false;
private boolean needInput = false;
private boolean skipped = false;
private int savedScannerPosition = -1;
private Object typeCache = null;
private boolean matchValid = false;
private boolean closed = false;
....
}
Scanner ์ด ๋ ์์ ๋ญ๊ฐ ๋๋ฌด ๋ง๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก 1KB์ Buffer๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
๊ทธ ์์ค์ buffer๋ User Defined Data Type์ด๋ค. ํ
public Scanner(InputStream source) {
this(new InputStreamReader(source), WHITESPACE_PATTERN);
}
public String nextLine() {
modCount++;
if (hasNextPattern == linePattern())
return getCachedResult();
clearCaches();
String result = findWithinHorizon(linePattern, 0);
if (result == null)
throw new NoSuchElementException("No line found");
MatchResult mr = this.match();
String lineSep = mr.group(1);
if (lineSep != null)
result = result.substring(0, result.length() - lineSep.length());
if (result == null)
throw new NoSuchElementException();
else
return result;
}
์ด๊ฑด Scanner ์์ฑ์๋ Input Method ์ฝ๋์ธ๋ฐ ์์ฑํ ๋๋ถํฐ ๋ฌด์จ ํจํด ๊ฒ์ฌ๋ฅผํ๊ณ ์ ๋ ฅ๋ฐ์ ๋๋ ํจํด ๊ฒ์ฌ๋ฅผ ํ๋ค.
์๋ ๊ทธ๋ฅ BufferedReader๋ณด๋ค ๋๋ฆด ์ ๋ฐ์ ์๋ค.
๊ทธ๋ผ์๋ ํจํด๊ฒ์ฌ๋ ๊ธฐ๋ฅ ์ธก๋ฉด์์๋ ์ฅ์ ์ด ์์ผ๋๊น ์ฌ์ฉํ๋ค.
Performance Test
public class InputTest {
public static void main(String[] args) throws IOException {
long startTime, endTime;
String input = "";
for (int i = 0; i < 100000; i++) {
input += "AAAAAAAAAAAAAAAAAAAA";
}
System.setIn(new ByteArrayInputStream(input.getBytes()));
// fread
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
startTime = System.nanoTime();
String line = br.readLine();
endTime = System.nanoTime();
System.out.println("BufferedReader read time: " + (endTime - startTime) + " ns");
System.setIn(new ByteArrayInputStream(input.getBytes()));
// read
Scanner sc = new Scanner(System.in);
startTime = System.nanoTime();
line = sc.nextLine();
endTime = System.nanoTime();
System.out.println("Scanner read time: " + (endTime - startTime) + " ns");
}
}
BufferedReader read time: 19981900 ns
Scanner read time: 102158800 ns
๊ทธ๋ฅ ๋ฐ์ดํฐ๊ฐ ์ปค์ง์๋ก ๋ฌด์ง์ฅ ์ฐจ์ด๋๋ค. ๋ฌด์กฐ๊ฑด PS์์๋ BufferedReader๋ฅผ ์ฌ์ฉํด์ผ๊ฒ ๋ค!
BufferedWriter vs System.out
BufferedWriter
public class BufferedWriter extends Writer {
private static final int DEFAULT_INITIAL_BUFFER_SIZE = 512;
private static final int DEFAULT_MAX_BUFFER_SIZE = 8192;
private Writer out;
private char[] cb;
public BufferedWriter(Writer out, int sz) {
this(out, sz, sz);
}
private void implFlushBuffer() throws IOException {
ensureOpen();
if (nextChar == 0)
return;
out.write(cb, 0, nextChar);
nextChar = 0;
}
}
์๋ ๋ง์ฐฌ๊ฐ์ง๋ก Buffer๋ฅผ ์ฌ์ฉํ๋๋ฐ ์์ธํ๊ฒ ๋ฏ์ด๋ณด์ง ์์๋ ๋ณ์๋ช ์ ๋ช ์ํด์ค ๋์ 512Byte ~ 8KB์ ๋ฒํผ๊ฐ ํ์ฉ๋๊ตฌ๋๋ฅผ ์์ํ ์ ์๋ค. ๊ทธ๋ฆฌ๊ณ BufferedWriter ๊ฐ์ฒด๋ฅผ ์ ๋ฏ์ด๋ณด๋ฉด write() ๋ฉ์๋๋ฅผ ์คํํ ๋, implFushBuffer() ๋ฉ์๋๋ฅผ ์คํํ๊ฒ ๋๋ค๋ ๊ฒ์ ์ ์ ์๋ค. ๊ทธ๋ฐ๋ฐ BufferedWriter์ implFushBuffer๋ out.write ๋ฉ์๋๋ฅผ ์ํํ๊ณ ์๊ณ out ๋ณ์์ ๊ฐ์ฒด๊ฐ Writer์ธ ๊ฒ์ ์๊ณ ์์!
System.out.print...
public final class System {
public static final PrintStream out = null;
}
public class PrintStream extends FilterOutputStream implements Appendable, Closeable {
private BufferedWriter textOut;
private OutputStreamWriter charOut;
private void implWrite(String s) throws IOException {
ensureOpen();
textOut.write(s);
textOut.flushBuffer();
charOut.flushBuffer();
if (autoFlush && (s.indexOf('\n') >= 0))
out.flush();
}
}
System ๊ฐ์ฒด์์ ์ถ๋ ฅ์ ํ๋ out์ PrintStream ๊ฐ์ฒด์ด๋ค.
์ฆ, ์ฐ๋ฆฌ๋ PrintStream ๊ฐ์ฒด์์ ์ ๊ณตํ๋ write() ๋ฉ์๋๋ก ์ถ๋ ฅ์ํ๋๋ฐ ์ด๊ฒ์ ๋ฏ์ด๋ณด๋ฉด BufferedWriter์์ ์ถ๋ ฅ์ ํ๊ณ ์๋ค๋ ๊ฒ์ด๋ค! ๊ทธ๋ผ BufferedWriter์์ Writer ๊ฐ์ฒด๋ก ์ถ๋ ฅํ๋ค๋ ๊ฒ์ ์์๋๋ฐ, ๊ฒฐ๊ตญ System.out ์ด๋ BufferedWriter๋ ๋ชจ๋ ๋ค Writer ๊ฐ์ฒด๋ก ์ถ๋ ฅํ๊ณ ์๋ค๋ ๊ฒ์ด๋ค.
๊ทธ๋ผ ๋๋์ฒด ์ BufferedWriter๋ฅผ ๋ฐ๋ก ์ฐ๋?
1. BufferedWriter๋ ์บ์ ํฌ๊ธฐ๋ฅผ ์ง์ ์์ ํ ์ ์๋ค.
2. System.out.print()๋ ๋งค๋ฒ Default ํฌ๊ธฐ์ BufferedWirter๋ฅผ ๋ถ๋ฌ์์ผ ํ๋ค.
3. System.out.print()๋ BufferedWriter์ ๋ฒํผ ์ธ์ charOut.flushBuffer(), out.flush() ๋ก ์คํธ๋ฆผ์ ๋น์ฐ๋ ์ถ๊ฐ ์์ ์ ํ๋ค.
์ดํดํ๊ธฐ ์ฝ๋๋ก ์ค๋ช ํ์๋ฉด,
1. BufferedWriter๋ 1kg ~ 1000kg ์ฉ๋์ ๋ด์ ์ ์๋ ์ฅ๋ฐ๊ตฌ๋๋ค.
2. System.out.print๋ 1kg ์ฅ๋ฐ๊ตฌ๋๋ง ์ง์ํ๋ค.
์ด๊ฒ์ผ๋ก ์ธํด ์ด๋ค ์ฐจ์ด๊ฐ ๋ฐ์ํ ๊น?
์ฐ๋ฆฌ๊ฐ ๋ฒํผ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ OS๋ก๋ถํฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ ๋น๋ฐ์์ผ ํ๋ค.
1. BufferedWriter๋ก ํ ๋ฒ์ 1000kg์ ๋ด์ ์ ์๋ ์ฅ๋ฐ๊ตฌ๋(๋ฉ๋ชจ๋ฆฌ)๋ฅผ ๊ตฌํ๋ค.
ํ ๋ฒ์ 1000kg์ ๋ฌผ๊ฑด(๋ฌธ์์ด)์ ๋ด๊ณ ๋ฐ๋ก ์ ๋ฌํ๋ค.
๋์ , ๋ฌผ๊ฑด(์์))์ด 1000kg(ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ๋)์ ์ด๊ณผํ ๊ฒฝ์ฐ ์ฌ๋ฌ๋ฒ ์ ์กํด์ผํ๋ค.
์ด ๋, 1000kg์ ๋ด์ฉ๋ฌผ์ ๋น์ฐ๊ณ ๋ค์ ์ฑ์ฐ๋๋ฐ ์๋นํ ์๊ฐ์ด ์์๋๋ค.
2. System.out.writer๋ก ํ ๋ฒ์ 1kg์ ๋ด์ ์ ์๋ ์ฅ๋ฐ๊ตฌ๋(๋ฉ๋ชจ๋ฆฌ)๋ฅผ ๊ตฌํ๋ค.
๋งค๋ฒ 1kg์ ๋ฌผ๊ฑด์ ๋ด๊ณ ์ ๋ฌํ๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก, ํ๋ฒ ์ ๋ฌ ์ ๋ฌผ๊ฑด์ด 1kg์ ์ด๊ณผํ ๊ฒฝ์ฐ ๋ด๋ถ์์ ์ฅ๋ฐ๊ตฌ๋๋ฅผ ๋น์ฐ๊ณ ๋ค์ ์ฑ์ฐ๋ ์๊ฐ์ด ์์๋๋ค.
์ฆ, ๋๋์ ๋ฌผ๊ฑด(๋ฐ์ดํฐ)์ BufferedWriter๋ก ์ ์กํ ๊ฒฝ์ฐ ํจ๊ณผ์ ์ด๋ค.
์๋์ ๋ฌผ๊ฑด๋ BufferedWriter๋ก ์ ์กํ ๊ฒฝ์ฐ ํจ๊ณผ์ ์ด๋ค. (๋์ ๋ฒํผ ํฌ๊ธฐ๋ฅผ ์ค์ฌ์ผํจ)
-> System.out.print.. ์ ๊ฒฝ์ฐ, ์คํธ๋ฆผ๋ ๋น์ฐ๋๋ฐ ์๋์ฐจ์์ ์ฅ๋ฐ๊ตฌ๋๊ฐ ์์นํ ์๋ฆฌ๋ฅผ ๊นจ๋ํ๊ฒ ์ฒญ์ํ๋ค๋ ์ ๋๋ก๋ง ์๊ฐํด๋ ๋ ๊ฒ ๊ฐ๋ค.
Performance Test
package com.study.datastructrue.io;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
public class OutputTest {
public static void main(String[] args) throws IOException {
long bufferStartTime, bufferEndTime;
long printStartTime, printEndTime;
int numIterations = 1000;
String data = "Hello World\n";
// large buffer, max size = 8 KB
BufferedWriter bwLarge = new BufferedWriter(new OutputStreamWriter(System.out), 8192);
long largeBufferStartTime = System.nanoTime();
for (int i = 0; i < numIterations; i++) {
bwLarge.write(data);
}
bwLarge.flush();
long largeBufferEndTime = System.nanoTime();
// default buffer = 512 Byte
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
bufferStartTime = System.nanoTime();
for (int i = 0; i < numIterations; i++) {
bw.write(data);
}
bw.flush();
bufferEndTime = System.nanoTime();
// System.out.print()
printStartTime = System.nanoTime();
for (int i = 0; i < numIterations; i++) {
System.out.print(data);
}
printEndTime = System.nanoTime();
System.out.println("BufferedWriter (default buffer) write time: " + (bufferEndTime - bufferStartTime) + " ns");
System.out.println("BufferedWriter (large buffer) write time: " + (largeBufferEndTime - largeBufferStartTime) + " ns");
System.out.println("System.out.print write time: " + (printEndTime - printStartTime) + " ns");
}
}
numIterators | 1 | 10 | 100 | 1000 | 10000 |
Default Buffer | 31100 ns | 158900 ns | 262700 ns | 24384500 ns | 196324900 ns |
Large Buffer | 156400 ns | 246900 ns | 407100 ns | 2100000 ns | 281576200 ns |
System.out | 38800 ns | 449300 ns | 2504500 ns | 26867900 ns | 263278000 ns |
๊ฐ PC์ ์ฑ๋ฅ๋ง๋ค ๊ฒฐ๊ณผ๋ ๋ค๋ฅด๊ฒ ์ง๋ง, Buffer๊ฐ ํด์๋ก ๋น์ฐ๋๋ฐ ์๊ฐ์ด ๊ฝค ์์๊ฐ ๋๋ค๋ ๊ฒ์ ์ ์๊ฐ ์๋ค.
PS์์๋ ๋๋ถ๋ถ ์ถ๋ ฅ๊ฒฐ๊ณผ๊ฐ 1000๊ฐ ์ดํ์ด๊ธฐ ๋๋ฌธ์ LargeBuffer๋ก ํด๋ ๋ ๋ฏ,,?
'JAVA > ๊ธฐํ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Java Fast I/O 3 (feat. BOJ, String, StringBuilder) (0) | 2024.07.06 |
---|---|
Java Fast I/O 2 (feat. BOJ, StringTokenizer, String.split()) (0) | 2024.07.06 |