[CS] Blocking I/O 과 Non-Blocking I/O, 병렬성 과 동시성의 차이에 대해 설명해주세요

Hocaron·2022년 9월 17일
5

CS

목록 보기
1/3

입출력을 기다리는 두 가지 방식, 멈추고 기다리기(Blocking I/O)와 멈추지 않고 기다리기(Non-Blocking I/O)

멈추고 기다리기(Blocking I/O)

  • 프로그램이 외부와 데이터를 주고 받을 때, 외부에서 데이터를 처리하는 동안 기다리는 것
  • 외부에서 작업을 진행하는 동안 프로그램의 자원은 외부 작업이 끝나기를 기다리는 데에 소비한다.

멈추지 않고 기다리기(Non-Blocking I/O)

  • 외부에서 필요한 작업을 하는 동안 프로그램은 다른 일을 할 수 있다.
  • 프로그램의 자원을 훨씬 효율적으로 사용할 수 있다.
  • 자신의 현재 맥락과 상관없이 외부 작업과 데이터를 공유할 방법이 필요하고, 이를 위한 추가 구현이 필요하다.

결과를 기다리는 방식에 따라 다시 분류되는 멈추지 않고 기다리기

  • 주도적으로 데이터를 가져오는 방식(Pull Base)을 사용하는 경우를 멈추지 않고 기다리기(Non-Blocking I/O)
  • 수동적으로 받아오는 방식(Push Base)을 사용하는 경우를 비동기 방식으로 입출력 기다리기(Asynchronous I/O)
  • 일반적으로 수동적으로 받아오는 방식이 자원을 훨씬 효율적으로 사용할 수 있지만, 주도적으로 가져오는 방식에 비해 구현해야 하는 코드가 많고, 복잡하다.

여러가지 일을 다루는 두 가지 방식, 병렬성(Parallelism)과 동시성(Concurrency)

병렬성

  • 작업을 처리하는 일꾼을 여러명 두어 같은 작업을 동시에 수행
  • 일꾼이 여러명이어야지 성립하는 개념이다.
  • 일꾼을 코어라고 생각하면, 두개 이상의 코어가 있어야 성립된다.

동시성

  • 일꾼이 여러가지 일을 동시에 수행
  • 일꾼의 수와는 상관없이 일꾼이 일하는 방식과 연관이 있다.
  • 일꾼이 하는 일들을 스레드라고 생각하면, 멀티스레드 방식인 경우 성립된다.

결론

  • 동시성은 자원을 효율적으로 사용하는 것이 목적이고, 병렬성은 많은 자원을 투자해서 일의 처리량을 늘리는 것이 목적이다.
  • 동시성과 멈추지 않고 기다리기를 같이 사용하면, 시너지 효과를 낼 수 있지만, 둘 사이에 의존성은 전혀 없다.
  • 동시성을 확보한 프로그램이 멈추지 않고 기다리기를 사용할 수도 있고, 사용하지 않을 수도 있다.

비동기 프로그래밍(Asynchronous Programming)

  • 실행한 코드의 결과를 기다리지 않고 별도의 채널에 결과 처리를 맡긴 후 다음 작업을 바로 진행하는 방식의 프로그래밍
  • 동시성(Concurrency), 멈추지 않고 기다리기(Non-Blocking I/O)와
    매우 흡사한 개념 같아 보이지만 독립된 정의로 다루어야 한다.

    ‘결과를 기다리지 않고 다음 코드를 실행하는 흐름’ 을 대표하는 개념이다. 이를 구현하기 위해 여러 일꾼을 사용하여 실행하도록 하든 일꾼 하나에 작업의 순서를 조절하여 실행하도록 하든, 어떻게 구현할 지는 비동기 프로그래밍과 연관이 있을 지언정 정의의 구성 요소라고 볼 수는 없다.
    🙋‍♀️이벤트 루프(Event Loop)를 사용하여 병렬성을 확보하지 않고 오직 동시성만
    으로 비동기 프로그래밍을 제공하는 방식이 있다.
    🙋‍♀️함수를 전달하여 처리하기(Callback) 방식을 사용하여 동시성 없이 비동기 프로그래밍을 제공할 수도 있다.

스레드 풀(Thread Pool)과 비동기 프로그래밍(Asynchronous Programming)

스레드 풀

  • 일의 단위를 스레드로 두고, 미리 만들어둔 스레드를 풀에서 필요할 때 하나씩 꺼내어 사용하고 일이 끝나면 다시 풀에 넣어 다른 일에 사용할 수 있는 상태로 두는 방식이다.
  • 병렬성과 동시성을 확보하여 작업을 효율적으로 수행하기 위한 기법이다.
1. 스레드 1이 일을 진행한다.
2. 비동기를 실행해야 할 코드를 만나면, 스레드 풀에서 스레드 2를 꺼내어 비동기로 진행할 일을 맡긴다. 스레드 1은 비동기 실행에 관여하지 않고, 나머지 일을 마저 진행한다.
3. 스레드 2는 일이 끝나면 약속에 맞게, Callback / Future, Promise 로 처리하고 다시 스레드 풀로 돌아간다.

스레드 풀을 구현체로 사용하는 비동기 프로그래밍을 사용 할 때 고려해야 할 사항

  1. 스레드 풀을 구현체로 사용하는 비동기 프로그래밍을 사용 할 때에는 오래 걸리는 작업으로 인해 스레드가 고갈되지 않도록 신경 써야 한다.
  • 이 문제를 해결하기 위해 오래 걸리는 작업만을 처리하기 위한 별도의 스레드 풀을
    사용하는 방식을 사용한다
  1. 비동기 작업 내부에서 일어나는 입출력을 되도록 멈추지 않고 기다리는 방식(Non-Blocking I/O)으로 처리해야 하는 점이다.
  • 스레드 풀을 사용하는 방식으로 비동기 프로그래밍을 지원하고 있다면 오래 걸리는 입출력 작업에 대해 되도록 멈추지 않고 기다리는 방식으로 처리하도록 해야한다.

references

profile
기록을 통한 성장을

0개의 댓글