본문 바로가기

개발기술/Computer Science

Blocking / Non-Blocking I/O

 

어플리케이션 레벨에서의 I/O 처리방식

 

I/O

  • Input과 Output, 데이터의 입출력
  • OS 상의 I/O의 종류로 Network(Socket), file, pipe, device가 존재함.
  • 네트워크 통신은 socket을 통해서 데이터가 입출력되며, 네트워크 요청자들은 각각 소켓을 열고 통신한다

 

Blocking I/O (블로킹)

  • I/O 작업을 요청한 프로세스/스레드는 요청이 완료될때까지 블락됨

 

Non-Blocking I/O (논블로킹)

  • 프로세스/스레드를 블락시키지 않고 요청에 대한 현재상태를 즉시 리턴
  • 요청을 보낸 후 해당 요청이 완료될 때까지 기다리지 않고 즉시 제어권을 반환합니다.
  • 요청을 처리하는 작업은 별도의 메커니즘(콜백, Future, 이벤트 루프 등)을 통해 비동기적으로 실행됩니다.

 

 

 

논블락킹 I/O 결과처리방식 :

  • Polling 방식
    • 쓰레드가 OS에 완료되었는지 반복적으로 확인하는 방식
    • OS에서 완료된 시간과 스레드에서 확인하는시간동안의 딜레이가 존재함
    • 쓰레드가 반복적으로 OS의 처리상태를 확인해야하기때문에 자원이 낭비됨
    • HTTP Polling과 Non-Blocking I/O Polling Http와는 다른 것임. 전자는 엄연히 blocking 방식임.
  • I/O Multiplexing(다중입출력) 방식
    • 쓰레드가 여러가지 관심있는 I/O 작업을 모니터링하고 소켓의 이벤트에 따라서 OS로부터 스레드가 알림을 받도록 요청하는 방식
    • 현재 주로 사용되고 있는 방식
    • epoll(리눅스), kqueue(맥), iocp(윈도우) : 관심있는 소켓들을 등록하고 OS로부터 스레드에게 알림을 받는것

  • Callback / Signal 방식  
    • OS에서 작업이 완료되면 바로 signal과 callback을 통해서 처리가 됨
    • POSIX AIO, LINUX AIO가 있음.
    • Callback이나 signal방식은 별로 사용되지는 않음?

 

 

이벤트 처리패턴

Polling, Interrupt, Event Loop 방식은 OS, 네트워크, 애플리케이션 등 여러 레벨에서 공통적으로 사용되는 프로그래밍 방식입니다.

개념 정의 사용되는 레벨
Polling
(폴링)
하나의 요청당 쓰레드가 이벤트가 발생했는지 주기적으로 확인하는 방식 OS(초창기 CPU Polling), 네트워크(Short Polling), 애플리케이션(Blocking HTTP)
Interrupt
(인터럽트)
하나의 요청당 쓰레드가 blocked 되고, 이벤트가 발생하면 알림(Signal or Interrupt)을 통해 처리 OS(하드웨어 인터럽트, 시스템 콜), 네트워크(TCP ACK), 애플리케이션(Blocking I/O)
Event Loop (이벤트 루프) 하나의 쓰레드가 여러 개의 이벤트를 감지하고 처리 OS(epoll, kqueue), 네트워크(SSE, WebSocket), 애플리케이션(Node.js, Netty)

 

여러 레벨에서 사용되는 Polling, Interrupt, Event Loop 패턴

OS 레벨에서의 패턴

  • 현재 운영체제(OS) 레벨에서 입력(input)이 들어온 것을 확인하는 방식은 이벤트 루프(event loop) 방식이 지배적입니다. 즉, 키보드, 마우스, 네트워크 소켓 등의 입력을 감지하는 이벤트 루프를 통해 I/O 이벤트가 발생하면 이를 처리하는 구조입니다.
    • 운영체제의 이벤트 루프는 인터럽트 기반이며, 필요할 때만 CPU를 깨우는 방식으로 동작합니다.즉, 커널에서 하드웨어 인터럽트를 통해 I/O 이벤트가 발생했음을 감지하고, 이를 이벤트 큐에 넣어 처리하는 구조입니다.
    • 외부 입력이 들어오면 스위치가 눌러지는 것과 같은 원리로 인터럽트가 발생하는 것이 가능합니다.
  • 현재는 3가지 방식을 적절히 섞어서 사용. 
    • 인터럽트 방식으로 최초 네트워크 패킷을 등록하고, 지속적인 연결이 필요할 시에 event loop가 감시하는 리스트에 등록하여 지속감시하는 방식으로 동작함.
방식 설명 예제
Polling
1950년대
각 소켓마다 개별 스레드가 존재하여 CPU가 계속적으로 I/O 상태를 확인 초창기 while (true) { if (ready) process(); }
Interrupt
1960년대 
각 요청마다 개별 스레드가 요청 후 응답될 때까지 blocked상태로 대기.
입력 발생시 하드웨어에서 입터럽트로 OS에 알리면 인터럽트 핸들러가 깨움
키보드 입력,
네트워크 패킷 최초 수신
Event Loop
1990년대 
OS의 이벤트 루프 스레드가 여러 소켓의 I/O 여부를 체크하고 애플리케이션에 notify epoll(), kqueue(), IOCP

 

 

 

Polling → Interrupt → Event Loop로 발전하는 이유

(1) Polling 방식의 한계

  • 이벤트가 없을 때도 CPU를 계속 사용하므로 비효율적.
  • 다중 I/O 처리를 할 때 확장성이 떨어짐.

(2) Interrupt 방식으로 개선

  • Polling 없이, 이벤트가 발생했을 때만 처리.
  • 하지만 응답이 올때까지 스레드가 Blocking 방식이므로 여러 개의 이벤트를 동시에 처리하기에는 스레드가 한계가 있음

(3) Event Loop 방식으로 최적화

  • 하나의 이벤트 루프가 여러 개의 이벤트를 감시하면서 효율적으로 처리.
  • 스레드가 대기하지 않고 다음 작업을 진행하여 비동기적으로 동작하며, 때문에 소수의 스레드로도 여러 개의 이벤트를 동시에 처리 가능.

'개발기술 > Computer Science' 카테고리의 다른 글

CS공부 - 네트워크  (0) 2024.06.22
CS공부 - 기타공부  (0) 2024.06.17
CS공부 - 운영체제  (0) 2024.06.16
CS공부 - 컴퓨터구조  (0) 2024.01.19
CS를 위한 이산수학 정리  (0) 2023.12.20