2005년 2월 11일 금요일

[펌] [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++){

댓글 없음:

댓글 쓰기