2013년 4월 29일 월요일

NIO2 AsynchronousFileChannel 사용 예제

작은 크기의 파일을 읽을 때에는 JDK 1.7 의 Files.readAllLines() 를 사용하면 땡입니다. 하지만 무지 큰 파일을 읽기, 쓰기를 할 경우에는 Disk IO 작업만으로 많은 시간이 걸려, 다른 작업을 못하게 됩니다. 이럴땐 무조건 비동기 작업으로 변환해야 합니다.

왜? 뭐하러? 비동기 작업이 만들기도 어렵고, 버그 발생 시 처리하기도 힘든데...
맞는 말이기도 하지만, 메모리와 CPU에서 처리하는 작업도 비동기 작업으로 처리하는데, 네트웍이나 DISK IO라면 수 천배, 수 만배 느린데, 이것을 비동기로 처리해서, 다른 작업을 처리해 줄 수 있다면 시스템 전체의 작업 효율이 엄청 높아질 것입니다.

Redis 가 초기에 Master/Slave replication 방식을 동기식으로만 지원하다가 비동기 방식도 지원하게 된 이유도 같은 이치라 보시면 됩니다.

자 이제 본격적으로 비동기 방식의 파일 읽기/쓰기를 해보기로 합시다. JDK 1.7 NIO 2 에 보면 기존 NIO 보다 확장되고 향상된 기능이 많습니다.
아직도 JDK 1.7을 쓰지 않는 시스템이나 NIO2 를 쓰지 않는 시스템을 보면 아쉬움이 크네요.
다들 얼른 빨리 업그래이드해서 고성능 기능을 활용하면 좋을텐데 하는 맘입니다.

우선 NIO 2 를 이용하는 방식 중 작은 파일을 다룰 때에는 버퍼링되는 스트림을 사용하는 것이  가장 쉽고, 편합니다.

BufferedReader, BufferedWriter 사용 법은 Files 클래스를 사용하면 끝납니다.


Files.newBufferedWriter, Files.readAllLines 등 내부적으로 BufferedReader, BufferedWriter를 사용합니다. 버퍼링을 통해, DiskIO 작업 횟수를 적게, 한꺼번에 처리하도록합니다.

다음으로는 대용량의 데이터를 파일로 처리할 경우 비동기 방식으로 처리해주는 AsynchronousFileChannel 의 사용법에 대해 보겠습니다. 이름에서 보시다시피 비동기 방식으로 파일의 데이터를 처리합니다.

대용량 데이터를 쓰는 예



데이터를 쓰는 경우도 많은 데이터를 쓰는 동안 다른 일을 처리할 수 있으므로, Future.isDone() 을 검사하여 다른 작업을 처리할 수도 있고, 다른 작업을 처리한 후 Future.get() 을 통해 작업 결과를 알 수 있습니다.

대용량 데이터를 읽는 예

데이터를 읽을 때, isDone() 은 UI 처리 등을 수행할 수 있고, 단순히 get() 으로 기다릴 수도 있습니다.
주의사항 : 테스트 코드라  읽고 난 후 파일을 삭제하게 해 놨으니, 실전에서는 필요에 따라 옵션을 지정해 주세요.

마지막으로 byte[]로 읽어드린 내용이 텍스트라면,  List 수형으로 변경해주는 것이 좋겠죠?
라인 처리는 OS 시스템마다 다 다른데, BufferedReader 가 잘 되어 있더군요 ㅋ

자 이렇게 BufferedReader 를 이용하여 작업을 처리했습니다.

댓글 없음: