11. Nonblock I/O

  • 네트워크 속도는 CPU뿐 아니라 디스크와 비교해도 느림.

    → 상대적으로 느린 네트워크를 엄청 빠른 CPU가 기다리게 하는 방법으로 해결

    → 버퍼링과 멀티스레드를 결합

    • 다수의 스레드가 다수의 연결을 통해 보낼 데이터를 생성

    • 네트워크가 데이터를 보낼 준비가 될 때까지 데이터들을 버퍼에 저장

      → 멀티스레드 생성, 스레드 전환(context-switch)시 발생하는 오버헤드가 큼

      → 하나의 스레드가 다수의 연결을 담당, 수신할 준비가 된 연결을 골라서 데이터를 처리하는 방법이면 더 빨라짐(nonblock I/O)

      JAVA NIO
      
      잘 설계된 nonblock I/O가 멀티스레드, 멀티프로세스 설계 방식보다 극적으로 성능을
      능가하던 시절이 있었음. JAVA 7 이후부터 context-switch와 동기화의 대부분
      오버헤드가 제거됨. 때문에 복잡한 NIO 기반의 구조가 단순한 스레드 기반의 구조보다
      낫다고 말하기가 어려워짐.
      (JAVA6기준 멀티스레드 I/O 설계방식이 NIO방식보다 30% 이상 뛰어남)

  • 채널 / 버퍼

    • 채널과 버퍼는 클라이언트 프로그램에서도 잘 동작하지만, 많은 동시 연결을 효과적으로 처리해야하는 서버 시스템을 위해 만들어짐

    • (추가로) 서버가 출력을 받거나 입력을 보낼 준비가 된 모든 연결을 찾을 수 있도록 도와주는 셀렉터(selector)가 필요함


  • Chnnel은 block mode로 실행됨.

  • ByteBuffer 객체를 사용하여 채널 자체에 직접 데이터를 쓸 수 있음.

    ByteBuffer buffer = ByteBuffer.allocate(74);
    int bytesRead = client.read(buffer);

버퍼

  • 채널(channel)/버퍼(buffer)은 block 기반인데 비해 스트림(stream)은 byte기반.

  • 채널과 버퍼는 같은 객체에 대해서 읽기와 쓰기 모두를 지원하는 경향이 있음.

  • 버퍼는 위치(position), 용량(capacity), 한도(limit), 표시(mark)등 네가지 주요 정보를 제공함

버퍼 만들기

  • 버퍼는 다형성이 아닌 상속에 기반을 두고 있음. (IntBuffer, ByteBuffer, CharBuffer인지 어떤 종류인지 알 필요가 있음)

  • 할당

    allocate()메서드는 고정 용량을 가진 빈 버퍼를 새로 생성하여 반환함

  • 직접 할당

    • allocateDirect() 메서드 제공.

    • DMA를 사용하여 버퍼에 직접적으로 할당된 ByteBuffer를 구현함

  • 랩핑(Wrapping)

    • 이미 데이터 배열을 가지고 있다면 버퍼를 새로 만들고 채우는 것 보다

      배열을 버퍼로 감싸는 편이 좋음(버퍼의 백업 배열처럼 제공됨)

채널

  • 채널은 파일, 소켓, 데이터그램 등과 같은 다양한 I/O 소스로부터 데이터 블록을 버퍼로 쓰거나 읽어온다. SocketChannel, ServerSocketChannel, DatagramChannel 클래스 세개가 중요.

  • SocketChannel 클래스로 TCP 소켓에 대해 읽고 씀. ByteBuffer 객체로 먼저 인코딩되어 있어야함.

Last updated