몇 번을 읽어도 이해가 안가는 말이었다. 영상강의에서도 이게 동기고 이게 비동기다라고 하는데 그냥 계속 헷갈려서 짜증났다. 그래서 그냥 순차 비순차로 이해하기로 했다.(철저하게 나만의 결정이다.) 순차 비순차로 이해하면 좀 더 쉽게 접근할 수 있다고 느꼈기 때문이다. 간단하게 예를 들어보자. 커피 주문 문제가 나오거나, 문자 vs 전화로 비교하는 얘기들이 많았다. 결국엔 같은 얘기일 수 밖에 없는게 이게 시킨 일만 쭈욱 하는건지, 시키다 딴일을 할 수 있는지에 대한 이야기다. 동기는 순차, 비동기는 비순차다.
그냥 단어그대로 이해하면되는데 순차같은 경우는 순차적으로 정해진 일들을 쭈우욱 실행하는 경우를 말한다. 코드를 통해 비교해보면, 간단한데, 동기 비동기 이전에 순차 비순차를 개념을 세워두면 이후에 진행될 callback이라던지, promise라던지, async & await가 이해가 쉬울 것이다.
예를 들어 순차 진행은 그냥 절차형 프로그래밍이다.
let a = 3; let b = 6; console.log(add(a,b));
다음과 같은 코드가 있다고 하면, 어떤 식으로 진행될지 눈에 보인다. 제일 위에 있는 것은 함수 선언문이니, 선언은 읽고 내려가고, a 값, b 값을 차례로 선언 초기화를 해주고 최종 줄에서 결국 console.log로 add(a,b) 함수의 결과값이 찍힌다. 이건 뭐 다르게 얘기할 것도 없이 차례로 내려오는 진행방식일 수 밖에 없다. 이런 코드진행을 나는 순차적이라고 부른다. 순차적인 방식은 컴파일러가 읽는 코드가 끝나야 다음 줄을 읽을 수 있다.
비순차 진행 같은 경우, 조건문이 걸려서 행이 이동하거나 다른 것에 의해서(나는 보통 컴파일러가 돌부리(함수)에 걸렸다고 얘기한다.) 코드 진행이 지연되는 경우를 뜻한다. 정말 간단하게 코드를 한 개 만들어보자.
let a = 100; let some = (a)=>{ a+= 100; } while(true){ a--; if(a === 1){ some(a); } else { //do nothing }
뭐 이런 난잡한 코드를 짰냐고 하겠지만, 그냥 내가 생각하는 비순차가 무엇인지 설명하기 위한 코드일 뿐이니까 코드가 구려도 그냥 넘어가도록 하자. 위에 순차적 진행과 다르게 비순차적 진행은 컴파일러가 읽는 방식이 많이 꼬여있다. 위 코드랑 유사한 부분이 많지만 기본적으로 while이 있기 때문에, 여기저기 돌아다니는 형태를 하고 있다. 이런 경우 코드가 어디로 굴러갔는지, 어디서 담아왔는지 다시 어디로 가는지를 살펴야되는데, 위 예제의 경우 while에서 지연되고 있다. 이런 경우를 나는 비순차라고 부른다.
다시 동기와 비동기로 돌아와서, 순차 비순차랑 무슨 상관이냐고 말하면 할 말이 없는데 기본적으로 딴길로 샐수 있냐 없냐를 말하는 것이다. 내가 이 짓을 하다가 딴 짓을 할 수 있느냐! 이게 main 주제다.
동기적 프로그램이라는 것은 결국엔 영화보는 것과 비슷하다.
웹페이지를 영화처럼 만들어놓고 쭈욱 보게끔해놓으면 사용자가 쓰기 힘들다. 지 혼자 버튼 누르고 지 혼자 상호작용하고 지혼자 이펙트 보여주고. 그냥 순차적으로 페이지를 동영상처럼 만들어두면 내가 이걸 이용하는건지 구경만하러 서있는건지 헷갈린다. 이렇게 되는 이유는 뭔가를 하다가 다른걸 할 수 없기 때문이다.
근데 사용자는 컴퓨터나 스마트폰을 쓰듯이 웹페이지를 이용해야한다.
영화를 보는게 아니라 '이용'이 주목적이기 때문이다. 나는 어떤 버튼을 누르다가 갑자기 마우스 휠을 내리고, 휠을 내리다가 멈춰서 월페이퍼를 보다가 갑자기 프로필을 확인하고 싶어지는 인간이다. 그 얘기는 웹페이지는 순차적으로 작동하는 것이 아니라, 상황에 따라서 변하는 조건에 맞추어서 동시에 실행되기도 하고(보기에는), 다른 기능을 동시에 수행하면서 움직여야한다. 그렇기 때문에 비동기적인 프로그래밍 절차가 필요해진다.
다음 사진은 코드스테이츠에서 제공해준 동기/비동기 작동 다이어그램
이다. 동기(synchronous)처리
를 보면 요청(request)이 생기면 task를 클라이언트에서 서버로 넘어가서 처리하는데, 처리하는 동안 다른 실행이 중지되고 대기상태(waiting for response)가 된다. 그에 반해, 비동기(asynchronous)처리
를 보면, 요청(request)가 생기면 서버 측에서 처리를 하면서, 클라이언트에서도 계속 진행상태(Continue working)이 된다. 그리고 서버 처리가 끝나면 다시 응답을 받아서 처리를 이어나간다.
위의 이미지를 보면 동기 처리의 경우 매번 함수 call이 불려질때마다, 해당 작업이 종료될 때까지 다른 작업없이 대기하다가, 다음 task를 받으면 다시 처리하는 식으로 계속적으로 전체 처리시간이 지연된다. 그에 비해 비동기처리는 동시에 여러 task를 handling할 수 있기 때문에 빠른 시간이내에 여러 작업을 처리할 수 있다.
다만 이 얘기는 처리속도와 다른 handling 문제가 발생될 여지가 있다는 것을 말해준다. 그 얘기가 무엇인고 하니..
ms(1/1000초) 단위로 완료되는 task를 비동기적으로 처리하려고 할때, 종료시점을 정확히 예측하고 실행의도에 맞게끔 실행하는 것이 굉장히 어렵다는 말이다. 가령, task1이 200ms에 끝나는 작업이라고했을 때, 다음에 뭐가 완료되어야할지에 대한 우선순위를 예측해서 코드를 작성하는 것은 인간의 입장으로서는 난감한 일이다.
그렇다면 비동기처리를 하는 방법엔 무엇이 있을까? 여러가지 방법이 있겠지만, 다음 글에서 다루기로 한다.