2008/11/15 01:09 else if (개발)
최근에 C라이브러리와 C라이브러리를 JNI로 래핑한 라이브러리의 성능을 비교하다가 C와 자바의 표준출력 차이에 대해서 알게되었습니다.

아래의 두 코드는 Hello World를 여러번 출력하는 초간단 자바와 C 코드입니다.

//test.c
#include <stdio.h>
int main() {
    int i;
    for (i = 0; i < 1000000; i++){
        printf("Hello World!\n");
    }
    return 0;
}

//Test.java
public class Test {
    public static void main(String[] args) {
        for (int i = 0; i < 1000000; i++) {
            System.out.println("Hello World!");
        }
    }
}

이렇게 간단한 두개의 코드를 컴파일하고 각각 실행시간을 time으로 재는데 단, 출력을 파일로 리다이렉션 합니다. 그 결과 두 프로그램의 실행시간 차이는 무려 다음과 같습니다.
$ time ./test > output1.txt
real    0m0.103s
user    0m0.050s
sys     0m0.050s

$ time java Test > output2.txt
real    0m9.885s
user    0m2.660s
sys     0m7.340s

이렇게 차이가 나는 이유는 출력 버퍼링의 차이 때문입니다.
C에서 표준출력은 터미널과 같은 대화형 장치에는 \n을 기준으로 flush를 하는 line buffering을 하지만, 파일로 리다이렉션 할 때는 full buffering으로 전환됩니다. 하지만, 자바의 System.out.println은 항상 line buffering을 하게 됩니다.
언어의 성능의 문제가 아니라 buffering 방식이 다르기 때문에 애초에 공정한 게임이 아닌 것입니다. 공정한 게임을 위해서는 자바 코드를 다음과 같이 수정해야 합니다.
import java.io.*;
public class Test {
    public static void main(String[] args) throws IOException {
        //표준출력 full buffering
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        for (int i = 0; i < 1000000; i++) {
            bw.write("Hello World!\n");
        }
        bw.close();
    }
}
$ javac Test.java
$ time java Test > output2.txt
real    0m0.294s
user    0m0.260s
sys     0m0.020s

자바와 C 프로그램의 성능을 비교하는데 표준출력을 파일로 리다이렉션 하면서 이 차이를 무시하면  아주 엉뚱한 판단을 하게 되겠죠? 제가 그랬습니다. T.T
posted by 심보준

Trackback | http://blog.sragent.pe.kr/trackback/12 관련글 쓰기

댓글을 달아 주세요

  1. 오홋, cout이랑 비교를 해보았더니 다음과 같네요.

    printf를 쓰면,
    real 0m0.148s
    user 0m0.132s
    sys 0m0.016s

    cout을 쓰면,
    real 0m2.982s
    user 0m1.302s
    sys 0m1.681s

  2. sragent 2008/11/20 09:57  Addr Edit/Del Reply

    cout << endl; // Send newline & flush --> 라임의 시험은 이것으로 보여짐
    cout << flush; // Flush only
    cout << ‘\\n’; // Send newline only

    즉,
    std::cout << "Hello World!" << std::endl; 하면 라인 단위로 flushing을 하고,
    std::cout << "Hello World!\\n"; 하면 C의 printf 처럼 buffering 을 하게됨.

  3. << 을 써서 당연히 느릴거야라고 생각을 하다가, 어케 그 차이가 안나게 해야 하나 좀 생각하다가 '\n'를 바꿔서 테스트해서 댓글 수정해야지 하고 들어왔는데. 그새 꼰대질을 하셨군요....^^;
    근데, printf("%s\n", string)보다 cout << "string\n" 이 더 빠른데요....^^; 이건 왜 그럴까요? iostream 객체를 써서 웬지 당연히 느릴 거 같은데 말입니당... 알켜주삼.

  4. 어? 왜 댓글 안달아놓으셨어요?
    컴파일 최적화 옵션 -O2를 넣으면 printf가 더 빨라진다고 하셔야죠. ㅋㄷㅋㄷ

prev 1 ... 23 24 25 26 27 28 29 30 31 ... 36 next