CS로 알아보는 프로젝트 - 동시성과 병렬성, 동기와 비동기 Feat: 코어와 스레드

안녕하세요.

 

오늘은 동시성과 병렬성에 대해 알아보도록 하겠습니다.

 

 

동시성 병렬성 혹시 구분이 가능하신가요??? 

 

그럼 동기와 비동기, 동시성과 병렬성을 명확하게 구분하실 수 있으신가요?? 

 

속으로 충분히 생각하고 스크롤을 내려보세요.

 

 

동시성과 병렬성을 이야기를 하기 이전에 싱글 코어와 멀티 코어에 대한 이해가 필요합니다. 

 

싱글 코어와 멀티 코어는 아래의 이미지처럼 동작하게 되는데요. 

 

좀 더 자세히 알아볼까요? 

 

 

 

쉽게 병렬성의 경우 2개 이상의 Core에서 동시에 작업을 처리하는 것을 의미합니다. 

 

아래 보이는 자료 처럼 2개의 코어가 각각의 스레드를 배치하여 안정적으로 처리가 가능한 모습을 확인할 수 있습니다. 

 

실제로 2개의 작업을 동시에 처리할 수 있게 되는 것이죠. (병렬적으로 처리가 가능)

 

그럼 동시성에 대해 알아볼까요? 

 

동시성의 경우 단일 코어에서 여러 스레드를 교차하면서 동시에 실행되는 것처럼 보이게 하는 것입니다.

 

그렇기 때문에 문맥 교환이 활발하게 이루어지게 되는 것이죠   

 

 

정리하자면 병렬성은 실제로 동시에 작업을 수행하는 것을 의미하는 것이고, 동시성은 빠르게 처리하여 동시에 동작하는 것처럼 보이게 하는 것입니다. 

 

 

쓰레드는 여러 개의 쓰레드가 동시에 실행될 수 있는 환경을 제공하기 위한 개념이지만, 실제로 여러 코어가 있는 경우에만 병렬 처리가 가능하다는 점 유의하시면 개념 잡기가 더욱 수월하실 거라고 생각합니다. 

 

 

그럼 코어와 스레드에 대해 자세히 알아볼까요?? 

 

1코어 2스레드, 1코어 4스레드 CPU를 구매하면서 혹은, CPU의 사양을 확인해보면서 들어보셨을거라 생각합니다. 

 

해당 의미를 명확하게 알고 계신가요? 

 

개념적으로 쉽게 접근하다면 아래 이미지와 같이

 

1코어 2스레드의 경우 1명의 세프가 2개의 팔을 가지고 일을 하는 것이고

1코어 4스레드의 경우 1명의 세프가 4개의 팔을 가지고 일하는 것입니다.  

 

프로그래밍 관점에서 접근해 볼까요?

  • 코어(Core): 하드웨어에서 연산을 처리하는 중심 부분. 코어 하나는 한 번에 하나의 명령어만 실행할 수 있음.
  • 스레드(Thread): 프로세스 내에서 실행되는 독립적인 실행 단위. 여러 스레드가 동시에 실행될 수 있음.
  1. 1코어 2 스레드:
    • 이는 하나의 코어에서 두 개의 스레드가 동시에 실행될 수 있음을 의미.
    • 코어 내에는 스레드를 실행하기 위한 두 개의 실행 컨텍스트(레지스터, 프로그램 카운터 등)가 있어 동시에 두 개의 스레드를 교차하며 실행할 수 있음.
    • 이 방식은 특정 스레드가 연산이 블로킹(blocking)되거나 대기(waiting) 상태에 있을 때 다른 스레드가 코어에서 실행될 수 있게 해 동시성을 증가시킴.
  2. 1 코어 4 스레드:
    • 이는 하나의 코어에서 네 개의 스레드가 동시에 실행될 수 있음을 의미.
    • 코어 내에는 스레드를 실행하기 위한 네 개의 실행 컨텍스트가 있어 동시에 네 개의 스레드를 교차하며 실행할 수 있음.
    • 더 많은 스레드를 동시에 실행할 수 있어 동시성을 더욱 향상할 수 있음.

 

그럼 3 코어 4 스레드의 경우 아래와 같은 이미지가 그려지게 되는 것 이죠

 

 

그럼 동기와 비동기, 동시성과 병렬성은 개념적으로 정말 다르다는 것을 이해하셨으리라 생각합니다.

 

그럼 동기와 비동기에 대해 한 번 알아볼까요?

 

동기 (Synchronous)

  • 동기는 순차적으로 작업을 실행하는 방식을 의미합니다.
  • 한 작업이 시작되면 완료될 때까지 다음 작업은 대기합니다.
  • 예를 들어, 함수를 호출하고 그 함수가 완료될 때까지 다음 코드는 실행되지 않습니다.

비동기 (Asynchronous)

  • 비동기는 작업을 동시에 실행하거나, 한 작업이 완료될 때까지 다른 작업을 계속할 수 있는 방식을 의미합니다.
  • 작업이 완료될 때까지 대기하지 않고 다음 작업을 계속할 수 있습니다.
  • 예를 들어, 비동기 함수를 호출하면 해당 함수는 백그라운드에서 실행되며, 결과를 기다리지 않고 다음 코드를 실행할 수 있습니다.

 

아래 이미지와 같이 동기 처리를 하게 되면 팀장은 팀원이 답을 줄 때까지 다음 작업을 수행할 수 없습니다.

 

다만, 비동기 처리를 하게 된다면 응답을 기다리지 않고 또 다른 일을 시킬 수 있는 것 이죠.

 

 

병렬성과 비교를 해본다면 병렬성을 각각의 독립된 공간에서 수행되는 반면, 비동기의 경우 동일 스레드에서 동작하는 것을 알 수 있습니다. 

 

그럼 단일 스레드에서 비동기는 어떤 식으로 동작하게 되는 것일까요?

 

Node.js와 같은 환경을 확인해 보면 힌트를 얻을 수 있습니다.  Node.js에서는 이벤트 루프를 활용하여 비동기 처리가 가능하게 됩니다.

 

단일 쓰레드 환경에서 비동기 처리는 주로 이벤트 루프(Event Loop)와 콜백(callback)을 통해 구현됩니다. 이러한 방식은 주로 웹 브라우저와 Node.js 같은 환경에서 사용됩니다.

이벤트 루프 (Event Loop)

  • 이벤트 루프는 단일 스레드에서 여러 비동기 작업을 관리하는 메커니즘입니다.
  • 이벤트 루프는 스레드가 단일 작업만 처리할 수 있는 환경에서도 여러 작업을 동시에 처리하는 것처럼 보이게 만듭니다.
  • 이벤트 루프는 작업을 큐(Queue)에 넣고, 이벤트 루프는 큐에 있는 작업을 순차적으로 실행합니다.

콜백 (Callback)

  • 비동기 함수는 일반적으로 콜백 함수를 인자로 받아 작업이 완료되면 해당 콜백 함수를 호출합니다.
  • 콜백 함수는 비동기 작업이 완료되었을 때 실행되며, 결과를 처리하거나 추가적인 작업을 수행할 수 있습니다.

 

추가적으로 궁금하신 아래와 같은 궁금증이 있는 분들이 있을 거라고 생각합니다.

 

Node 가 단일 스레드라고요? 여러 스레드가 일을 나눠서 할 수 있는  worker threads라는 개념이 있는데요??? 

 

그렇지만 어떤 책을 찾아봐도 어떤 CS 지식을 찾아봐도 Node는 단일 스레드라고 명시되어 있습니다. 

 

그 이유는 무엇일까요? 

 

바로 Node는 기본적으로 JavaScript의 이벤트 루프를 메인 스레드로 활용하기 때문에 "싱글 스레드"라고 불리게 됩니다.

 

worker threads를 사용하여 스레드를 생성하더라도 이벤트 루프가 하나 더 생기는 것이 아닌 이와 상호작용하는 스레드가 생기기는 것이기 때문입니다.