블록킹과 논블록킹 & I/O와 N/I/O

김채현·2024년 1월 3일

블록킹(Blocking)

블록킹은 다른 작업이 완료될 때까지 현재 작업을 중단하는 방식입니다.
블록킹은 단순한 작업에 적합합니다. 예를 들어, 파일에서 데이터를 읽거나 쓰는 간단한 작업을 수행할 때 블록킹을 사용할 수 있습니다. 블록킹은 구현이 간단하고 이해하기 쉽다는 장점이 있습니다.

블록킹 예시)

  • 파일에서 데이터를 읽는 작업
  • 네트워크에서 데이터를 수신하는 작업
  • 데이터베이스에서 데이터를 조회하는 작업

논블록킹(Non-Blocking)

다른 작업이 완료될 때까지 현재 작업을 중단하지 않는 방식입니다.
논블록킹은 고성능 작업에 적합합니다. 예를 들어, 네트워크에서 데이터를 전송하거나, 파일에서 대량의 데이터를 읽거나 쓰는 작업을 수행할 때 논블록킹을 사용할 수 있습니다. 논블록킹은 성능이 높지만, 구현이 복잡하고 이해하기 어려울 수 있습니다.

블록킹과 논블록킹은 동기(Synchronous)와 비동기(Asynchronous)와도 밀접한 관련이 있습니다. 동기는 작업이 완료될 때까지 기다리는 방식이고, 비동기는 작업이 완료될 때까지 기다리지 않는 방식입니다. 따라서 블록킹은 동기와 같은 의미로 사용되기도 합니다.

논블록킹 예시)

  • 파일에서 데이터를 비동기식으로 읽는 작업
  • 네트워크에서 데이터를 비동기식으로 수신하는 작업
  • 데이터베이스에서 데이터를 비동기식으로 조회하는 작업
특징블록킹논블록킹
다른 작업 완료 여부에 따른 스레드 상태동기비동기
성능저성능고성능
복잡성낮음높음
사용예단순 작업고성능 작업

블록킹과 논블록킹은 동기(Synchronous)와 비동기(Asynchronous)와도 밀접한 관련이 있습니다. 동기는 작업이 완료될 때까지 기다리는 방식이고, 비동기는 작업이 완료될 때까지 기다리지 않는 방식입니다. 따라서 블록킹은 동기와 같은 의미로 사용되기도 합니다.

I/O

I/O는 Blocking I/O의 약자로, 입출력 작업이 완료될 때까지 해당 작업을 요청한 스레드를 차단합니다. 예를 들어, 파일에서 데이터를 읽는 작업을 수행한다고 가정해 보겠습니다. 이때 I/O를 사용하면 파일에서 데이터를 읽을 수 있을 때까지 해당 스레드는 대기 상태가 됩니다.

I/O 작업은 일반적으로 다음과 같은 단계로 수행됩니다.

  1. 작업을 요청하는 스레드가 차단됩니다.
  2. 작업이 완료되면 작업을 요청한 스레드가 해제됩니다.

자바에서는 InputStream과 OutputStream을 사용하여 I/O 작업을 수행할 수 있습니다.

FileInputStream fis = new FileInputStream("data.txt");
byte[] bytes = new byte[1024];
int read = fis.read(bytes);  //blocking

이 코드에서는 read() 메서드가 데이터를 모두 읽을 때까지 스레드가 차단됩니다. 즉, read() 메서드가 데이터를 읽을 수 있을 때까지 스레드는 대기 상태가 됩니다.

예를 들어, 파일에서 데이터를 읽는 작업을 수행하는 경우 다음과 같은 단계로 수행됩니다.

  1. read() 메서드를 호출하는 스레드가 차단됩니다.
  2. 파일에서 데이터를 읽는 작업이 완료되면 read() 메서드가 반환됩니다.
  3. read() 메서드가 반환되면 차단되었던 스레드가 해제됩니다.

이러한 방식으로 I/O 작업을 수행하면 작업이 완료될 때까지 스레드가 대기 상태가 됩니다. 따라서 I/O 작업이 자주 발생하는 경우 성능이 저하될 수 있습니다.
N/I/O는 이러한 문제를 해결하기 위해 도입된 방식입니다. N/I/O는 작업을 요청하는 스레드를 차단하지 않고 작업이 완료될 때까지 대기하는 별도의 스레드를 생성하는 방식으로 수행됩니다.

N/I/O

N/I/O는 Non-Blocking I/O의 약자로, 입출력 작업이 완료될 때까지 해당 작업을 요청한 스레드를 차단하지 않습니다. 예를 들어, 파일에서 데이터를 읽는 작업을 수행한다고 가정해 보겠습니다. 이때 N/I/O를 사용하면 파일에서 데이터를 읽을 수 있는 데이터가 있을 때까지 해당 스레드는 다른 작업을 수행할 수 있습니다.

아래는 N/I/O를 사용하여 파일에서 데이터를 읽는 코드입니다.

AsynchronousFileChannel afc = AsynchronousFileChannel.open(Paths.get("data.txt"));
afc.read(ByteBuffer.allocate(1024), null, new CompletionHandler<Integer, Void>() {
    @Override
    public void completed(Integer result, Void attachment) {
        // 데이터를 읽은 후 처리할 작업
    }

    @Override
    public void failed(Throwable exc, Void attachment) {
        // 데이터 읽기 실패 시 처리할 작업
    }
});

이 코드는 read() 메서드를 호출하여 파일에서 데이터를 읽습니다. read() 메서드는 CompletionHandler 객체를 인수로 받습니다. CompletionHandler 객체는 데이터 읽기가 완료되었을 때 또는 실패했을 때 호출됩니다.

이 코드에서는 read() 메서드가 데이터를 읽기 시작하면 스레드는 다른 작업을 수행할 수 있습니다. read() 메서드가 데이터를 모두 읽으면 CompletionHandler 객체의 completed() 메서드가 호출됩니다.

위 코드의 파일에서 데이터를 읽는 작업을 수행하는 경우 다음과 같은 단계로 수행됩니다.

  1. read() 메서드를 호출하는 스레드는 다른 작업을 수행할 수 있습니다.
  2. 파일에서 데이터를 읽는 작업이 완료되면 작업을 완료한 스레드가 CompletionHandler 객체를 호출합니다.
  3. CompletionHandler 객체는 데이터를 읽은 후 처리할 작업을 수행합니다.

이러한 방식으로 N/I/O 작업을 수행하면 작업이 완료될 때까지 스레드를 차단하지 않기 때문에 성능을 향상시킬 수 있습니다.

자바의 I/O와 N/I/O는 모두 입출력 작업을 수행할 때 사용됩니다. 그러나 I/O는 작업이 완료될 때까지 스레드를 차단하는 반면, N/I/O는 작업이 완료될 때까지 스레드를 차단하지 않는 차이점이 있습니다.
따라서 I/O는 단순한 입출력 작업을 수행할 때 사용되고, N/I/O는 고성능 입출력 작업을 수행할 때 사용됩니다.

I/O를 사용하는 작업의 예시)

  • 파일에서 데이터를 읽거나 쓰는 작업
  • 네트워크에서 데이터를 전송하거나 수신하는 작업
  • 데이터베이스에서 데이터를 조회하거나 저장하는 작업

N/I/O를 사용하는 작업의 예)

  • 네트워크에서 대량의 데이터를 전송하는 작업
  • 파일에서 대량의 데이터를 읽는 작업
  • 데이터베이스에서 대량의 데이터를 조회하는 작업
특징I/ON/I/O
입출력 작업 완료 여부에 따른 스레드 상태차단비차단
성능저성능고성능
복잡성낮음높음
사용예단순 작업고성능 작업
입출력 방식스트림채널(양방향 입출력 가능)

0개의 댓글