동기 vs 비동기 I/O

Jaemyeong Lee·2025년 1월 25일

게임 서버1

목록 보기
135/220

먼저 축(Axis)을 분리하자

블로킹 vs 논블로킹 (호출 반환 시점)

구분블로킹(Blocking)논블로킹(Non-blocking)
핵심 질문"호출한 스레드가 기다리는가?""호출이 즉시 돌아오는가?"
반환 시점작업 가능 상태가 될 때까지 대기즉시 반환
대표 예시recv() (기본 소켓)논블로킹 소켓의 recv()
흔한 결과 코드대기 후 성공/실패준비 전이면 WSAEWOULDBLOCK

동기 vs 비동기 (완료 통지 시점)

구분동기(Synchronous)비동기(Asynchronous)
핵심 질문"반환 시점에 작업이 끝났는가?""완료를 나중에 통지받는가?"
완료 확인 방식호출 결과를 즉시 확인이벤트/콜백/완료 큐에서 나중 확인
대표 예시recv 반환값으로 결과 확인WSARecv(Overlapped) + 완료 통지

핵심 결론

  • 블로킹/논블로킹과 동기/비동기는 서로 다른 축입니다.
  • 따라서 "논블로킹이면 자동으로 비동기"가 아닙니다.

2x2 매트릭스로 정리

동기(Sync)비동기(Async)
블로킹일반 recv/send (대기 후 완료)개념적으로 가능하나 일반 Winsock 실무에서는 거의 사용되지 않음
논블로킹recv 즉시 반환 + WSAEWOULDBLOCK 재시도 패턴Overlapped/IOCP: 요청 후 나중에 완료 통지

실무에서 자주 쓰는 3가지

  1. 블로킹 + 동기: 가장 단순, 소규모/학습용
  2. 논블로킹 + 동기: 이벤트 루프 + 재시도(폴링/준비확인)
  3. 논블로킹 + 비동기: 고성능 서버(Overlapped, IOCP)

타임라인 감각

sequenceDiagram
    participant T as Thread
    participant K as Kernel

    rect rgb(245, 245, 245)
    Note over T,K: Blocking + Sync (recv)
    T->>K: recv 호출
    K-->>T: 데이터 준비 시 반환(완료)
    end

    rect rgb(245, 250, 255)
    Note over T,K: Non-blocking + Sync (recv)
    T->>K: recv 호출
    K-->>T: 즉시 반환(WSAEWOULDBLOCK 가능)
    T->>K: 나중에 다시 recv 호출
    K-->>T: 준비 시 반환(완료)
    end

    rect rgb(245, 255, 245)
    Note over T,K: Non-blocking + Async (WSARecv Overlapped)
    T->>K: WSARecv 요청 등록
    K-->>T: 즉시 반환(WSA_IO_PENDING 가능)
    K-->>T: 나중에 완료 통지(Event/IOCP)
    end

WSAEWOULDBLOCK vs WSA_IO_PENDING

둘을 섞어 이해하면 안 된다

항목WSAEWOULDBLOCKWSA_IO_PENDING
주로 나오는 맥락논블로킹 recv/send/acceptOverlapped 비동기 요청
의미"지금은 준비 안 됨, 나중에 다시 시도""요청 등록됨, 완료는 나중에 통지"
코드 패턴재호출/준비 이벤트 감시완료 이벤트/IOCP 대기
성격즉시 완료 실패(재시도 필요)비동기 진행 중(정상 경로)

최소 코드 비교

// 1) Non-blocking + Sync
int ret = recv(sock, buf, len, 0);
if (ret == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK) {
    // 아직 읽을 데이터 없음: 나중에 다시 recv
}

// 2) Non-blocking + Async (Overlapped)
DWORD flags = 0, bytes = 0;
int r = WSARecv(sock, &wsaBuf, 1, &bytes, &flags, &ov, nullptr);
if (r == SOCKET_ERROR && WSAGetLastError() == WSA_IO_PENDING) {
    // 정상: 요청은 등록됨, 완료 통지를 기다린다
}

비동기 != 멀티스레드

관점 분리

  • 비동기는 "완료를 언제 알리느냐"의 문제입니다.
  • 멀티스레드는 "어느 스레드가 일을 하느냐"의 문제입니다.

예시

  • 단일 스레드 이벤트 루프도 비동기 구조를 만들 수 있습니다.
  • IOCP는 비동기 I/O + 워커 스레드 풀을 결합한 고성능 모델입니다.

설계 판단 기준

  • 동접이 작고 단순하면 동기 모델로도 충분
  • 동접/트래픽이 커지면 비동기 완료 기반 모델이 유리
  • 스레드 수를 늘리기 전에, 대기 방식(블로킹/비동기)을 먼저 점검

강의 시 유의사항

강조 포인트

  • 이 파트의 목적은 "용어 암기"가 아니라 "축 분리 사고"입니다.
  • 다음 Part 17(Overlapped)과 Part 18(IOCP)을 이해하려면 이 구분이 선행되어야 합니다.
  • WSAEWOULDBLOCKWSA_IO_PENDING의 의미 차이를 반드시 비교해 설명하세요.

자주 하는 오해

오해바로잡기
논블로킹이면 비동기다논블로킹 + 동기 모델도 흔하다
비동기는 반드시 멀티스레드다단일 스레드 이벤트 루프도 비동기 가능
WSA_IO_PENDING은 에러다비동기 요청이 정상 등록됐다는 신호

체크 질문 (스스로 답해보기)

  • 왜 블로킹/논블로킹과 동기/비동기를 하나의 축으로 보면 안 되는가?
  • WSAEWOULDBLOCKWSA_IO_PENDING을 각각 어떤 상황에서 처리해야 하는가?
  • 내 서버가 동접 1만 이상으로 증가할 때 어떤 조합으로 전환할지 기준을 세워보라.

profile
李家네_공부방

0개의 댓글