JavaScript는 다른 언어들과 다르게, 특이한 흐름이 있습니다. JS는 "싱글 쓰레드"언어이지만, 동시성을 갖고 있는 언어이기도 합니다. 이게 무슨말인지 잘 와닿지 않을 수 있습니다. 여기서는 CS지식이 들어갈 수 밖에 없고, 저는 다행히 전공을 했기 때문에 이해가 가지만, 어려운 개념에는 틀림이 없습니다! 천천히 가보죠!
동시성(Concurrency)
프로그램 처리 관점에서 Concurrency는 "동시에 수행하는 것 처럼 동작시키는 것"을 이야기합니다. 아래의 예시를 보시죠. 어떤 작업 Task1,Task2가 듀얼코어의 CPU 시스템에서 처리된다고 생각해봅시다. cpu는 1개의 task밖에 처리를 못한다고 가정하겠습니다.
이런상황에서 , task 3,task 4를 진행시키고 싶은겁니다. 다른 말로 더 와닿게 말씀드리면, 브라우저 키고, 노래 듣고, 카톡도 하면서 , VScode도 하고 싶은겁니다.
어떻게 할 수 있을까요? 수십장의 그림을 빠르게 넘기면, 우리 눈에는 움직이는것처럼 보입니다. 즉, 끊기지 않고, 연결된 것처럼 보인다는 이야기죠. 마찬가지로, 작업도 인간이 인지할 수 있는 속도보다 빠르게, 바꿔치기 하면서 조금씩 작업하면, 마치 끊기지 않는것처럼 느껴지지 않을까요? 아래와 같이 말이죠! 이게 ,"동시성" 입니다. 대표적으로 , 시분할 방식을 쓰는데, OS정리할 때 다시 다루도록 하겠습니다.
병렬성(Parallelism)
병렬성은 말 그대로, 다른 CPU에서 처리하는걸 이야기합니다. 동시성은 Task를 바꿔주는데 비용이 발생합니다. 병렬성은 이런 과정이 필요없습니다. 진짜 물리적으로 분리되어 있는 공간에서 실행시켜주는 거입니다. CPU1,CPU2에서 task (1,3) (2,4)는 병렬적으로 처리되는걸 병렬성이라고 합니다.
스레드와 프로세스 , 컨텍스트 스위칭 (Context Switching)
프로세스는 운영체제로부터, 자원(메모리)을 할당받는 작업 단위입니다.
스레드는 할당받은 자원을 이용하는 "실행의 단위"라고 할 수 있습니다. 프로세스 내에 여러개의 스레드가 실행되는거죠.
Multi Process
하나의 프로그램을 여러개의 프로세스로 구성해서, 각 프로세스가 하나의 작업을 처리합니다. 즉, 메모리 공간을 추가적으로 OS에서 할당받아서 실행하는 방법입니다. 이때, 각 프로세스를 번갈아 가면서 실행(동시성)하게 되는데, 이 작업을 Context Switching이라고합니다. 프로세스는 독립적인 메모리 공간이므로, cache hit율도 낮습니다. 즉, 캐시메모리 초기화 작업을 해야합니다. 또, 메모리 영역을 할당받는다는 건 "System Call" 즉, OS를 통해서 커널모드로 바꿨다가, 사용자 모드로 전환하는 추가작업도 필요합니다. 하지만, 안정적입니다.
Multi Thread
멀티 쓰레드는 , 하나의 프로세스 안에서 여러개의 스레드로 자원을 공유하며 작업을 나누어 수행합니다. 즉, context switching 이 매우 빠르겠죠. 쓰레드는 기본적으로 "Function Call"이기 때문에, 시스템 콜이 줄어들어 빠르고, 한 프로세스 내에 있기 때문에, cache의 hit율도 높습니다.
하지만, 프로세스를 하나의 컨테이너처럼 사용해서, 여러개의 자원을 공유해서 사용한다는 말은 곧, 여러 쓰레드에서 동시에 접근 할 수 있다는 이야기 입니다. 공유자원을 보호하기 위해서, 동기화(Mutex,spinlock,Semaphore 등의 개념)를 잘 해줘야하고 , 그리고, 구현하기도 까다롭습니다(실수할 확률이 높다 , 사람마다 구현하는 결과물이 천차만별이다).
* JS는 Single Thread입니다. 즉, 1개의 스레드만 돌아간다는거죠! 1번에 1개의 작업만 가능!
들어가기 전에, 블로킹과 논블로킹, 동기와 비동기는 완전히 다른 관점에서 보는겁니다. 둘을 혼동하면 안됩니다!
블로킹 & 논 블로킹
블로킹은 말 그대로 , "blocking" 실행이 막히느냐 안막히느냐의 관점으로 해석을 한겁니다.
Blocking은 하나의 작업이 끝날 때 까지, 다른 작업을 하지 않습니다. 즉 , 제어권을 B에게 넘긴다음, B가 다시 제어권을 넘길때 까지 아무런 작업을 못합니다. 만약, JS가 Blocking이라면, Ajax요청을 보내면 , 요청이 끝날 때 까지 아무런 화면 클릭도 못할겁니다.
논 블로킹은 반대로, 제어권을 그대로 가지고 있는 상태로, 다른 함수를 "실행"만 시키는 형태입니다. 다른함수가 실행될 동안, 나는 내 할일을 하게됩니다.
Synchronous & Asynchronous
동기와 비동기는 프로세스의 수행 순서가 보장되느냐 관점입니다. 동기이면, 내가 지정한 순서대로 프로세스가 돌아가는걸 이야기합니다. Code로 따지면, Top-down으로 코드의 흐름이 생성되냐/안되냐에 따라서 나누는거죠!
함수로 따지면, 호출하는 함수 A가 호출되는 함수 B의 작업이 "언제"완료되는지 계속 물어봅니다.
비동기는 함수A가 함수 B를 호출할 때, 함수 B의 실행 순서를 신경쓰지 않습니다. 언제 실행되는지 모르고, 알 필요도 없고, 그냥 관심이 없습니다. 주로 Callback으로 구현합니다. code로 따지면, Top-down으로 코드의 흐름이 생성되지 않습니다.
* JS에서 EventListener, SetTimeout등이 비동기라고 불리는 이유는, 코드 상에서 Top-down으로 실행되지도 않고, 단지 Web API를 통해서 callback으로 등록하고 있을 뿐입니다.
보통 비동기 & non -blocking , 동기 & blocking을 조합하여 씁니다. 그리고, 간혹가다가 동기&non-blocking도 있습니다.
동기&non-blocking은, A의 함수 자신을 계속 실행하면서, B의 함수의 리턴값이 필요할 때 사용되어집니다. 즉, 중간중간에 계속 함수실행이 완료되었는지 물어보는 상태를 이야기합니다. 로딩창이 보통 그렇습니다. 자신은 계속 실행하면서, 상대방에게 끝났냐 ,끝낫냐 계속 체크를 하니까요.
JS는 비동기 ,non-blocking입니다. 왜 그런지는 다음 글에 담도록하죠!
'Computer Science' 카테고리의 다른 글
[웹 통신/Protocol/HTTP] 웹 통신과 HTTP에 대해서 (1) | 2022.09.22 |
---|