본문 바로가기

Dev.../플밍 관련 자료

[펌] [java성능] 5.IO Streams.doc

※이 문서는 Java Performance and Scalability Volume1(by Dov Bulka)라는 책의

5:I/O Streams 읽고 나름대로 정리한 것입니다.

 

Preface

 자바의 I/O stream socket, file, string, character array 등등을 끝단으로 해서 데이터를 읽고 있다. 이러한 I/O 들의 성능 문제를 언급하기 위해서 전체를 다룰 필요는 없을 같다. 우리가 원하는 것은 실제 I/O 장치와 stream 클래스와의 상호작용의 기본적인 성능 원리를 이해하는 것이므로 file I/O 관한 stream 살펴보는 것만으로도 충분할 것이다. Java에서  I/O stream 이용하여 데이터를 읽고 쓰는데 있어서 가장 중요한 문제는 버퍼링과 유니코드 변환 문제이다. 이번 장에서 다루는 모든 최적화는 둘중의 하나이다.

 

Example I/O Code

 이번장에서 사용하는 예제들은 I/O stream 통해 주로 데이타를 읽기만 하거나 쓰기만 것이므로 쓰여질 데이터가 코드를 미리 작성해 둔다. 간단한 주식거래에 대한 클래스로 거래 날짜, 매도(매수), 주식 심볼, 거래 주식수, 주식 가격만을 정보로 가진다고 하자. 그러면 대충 필요한 겉모양은 나온다.

class Trade{

             String date;

             boolean buy;

             int numShares;

             String symbol;

             float price;

             ...

}

 Trade 객체를 파일에 기록한다면 (1)이나 (2)처럼 사용할 것이다.

(1)  Trade buy = new Trade(“01-01-99”, true, 100, “IBM”, 140);

   fw.println(buy); //fw is a FileWriter

(2)  fos.write(buy.toString().getBytes());  //fos is FileOutputStream

println() 메소드는 Trade.toString() 호출할텐데 이는 다소 비싼 작업이다. 여기에서는 I/O 성능에 관해서 이야기를 것이므로 이러한 부분들이 성능 비교에 영향을 미치지 못하도록 클래스를 적절히 수정하도록 하겠다. 생성자에서 String이나 byte 미리 변환을 시켜놓고 toString()이나 toBytes() 메소드는 단지 이에 대한 레퍼런스 값만을 넘기게 함으로써 I/O 작업을 위해 String값이나 byte값을 매번 요구하더라도 값을 넘겨주는 작업은 성능에 거의 영향을 미치지 않게 된다. 코드는 아래와 같다.

 

class Trade{

   String date;

   boolean buy;

   int numShares;

   String symbol;

   float price;

  

   String stringRep;

   byte[] byteRep;

  

   public Trade(String d, boolean b, int n, String s, float p){

          symbol = s;

          numShares = n;

          buy = b;

          date = d;

          price = p;

 

          StringRep = privateToString(); //String으로 미리 변환

          byteRep = stringRep.getBytes(); //byte 미리 변환

   }

   private String privateToString(){

          StringBuffer sb = new StringBuffer(128);

          sb.append(date).append(“ ”);

          if(buy) sb.append(“Buy “);

          else sb.append(“Sell “);

          sb.append(numShared).append(“ ”);

          sb.append(symbol).append(“ ”);

          sb.append(price).append(“ ”);

          return sb.toString();

}     

 

public String toString(){

       return stringRep;

}

 

public byte[] toBytes(){

       return byteRep;

}

}

 

 

1. Output Buffering

 버퍼링은 바이트당 오버헤드를 최소화 있는 기법이다. 데이터를 보내기 위해서 자바에서는 OS 자체의 함수를 콜해야 하는데, OS 함수 자체는 한번 콜하는데 드는 비용이 바이트를 보내나 여러 바이트를 보내나 비슷하다( 비용 또한 만만치도 않다). 그러므로 한번에 바이트씩만 보낸다면 여러 바이트를 묶어서 한번에 보내는 것보다 엄청나게 비싼 댓가를 치러야 되는 것은 자명한 사실이다. 자바에서 I/O stream 이용해서 버퍼링을 하는 것은 아주 쉽다. 단지 원래의 output stream buffered stream으로 감싸기만 하면 된다.

 여기에서는 Trade 객체를 FileOutputStream 이용해서 파일에 기록할 버퍼링이 얼마나 나은 결과를 가져 오는지 보여주고자 한다. 첫번째 예제는 버퍼링 없이 FileOutputStream 사용하였고 두번째 예제는 버퍼링을 사용하였다.

 

[예제1] 수행시간 : 33

       Trade buy = new Trade(“01-01-88”,true,100,”IBM”,140);

       Trade sel = new Trade(“01-08-88”,false,100,”IBM”,150);

       FileOutputStream fos = new FileOutputStream(“stock.dat”);

       for(int i=0; i<1000000; i++){