어플리케이션 레벨에서의 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 |