[면접준비] 동기/비동기, deadlock (24/04/22)

2024. 4. 22. 09:37공부/면접 준비

동기/비동기

  1. 동기(Synchronous)
    • 순차적/직렬적으로 태스크를 수행한다
    • 요청을 보냈다면, 응답을 받아야 다음 동작이 이루어진다
    • 순차적으로 실행되므로, 어떤 작업이 수행중이라면 뒤의 작업은 대기한다
    • 블로킹(작업 중단)이 발생한다
      • 동기적으로 데이터를 서버로부터 받아오는 앱을 만든다고 가정하면, 데이터를 받아오기 까지 기다린 후 앱이 실행될 것이고 서버에 가져오는 데이터 양이 늘어날수록 실행 속도가 느려질 것이다.
      • 이러한 불편함을 해결하기 위해 데이터 수신과 페이지 표시가 비동기적으로 처리되어야 한다.
      • stTimeout과 AJAX
    • function func1() {
          console.log('첫번째 펑션!');
          func2();
      }
      
      function func2(){
          console.log('두번째 펑션!');
          func3();
      }
      
      function func3() {
          console.log('세번째 펑션');
      }
      
      func1();
      // 출력값은 아래와 같다.(순서대로 처리)
      // 첫번째 펑션!
      // 두번째 펑션!
      // 세번째 펑션! 을 띄우게 된다.
  2.  비동기(Asynchronous)
    • 병렬적으로 태스크를 수행한다
    • 현재 작업의 종료여부와 무관하게 다음 작업을 실행한다
    • 그러므로 동기 방식과는 달리 완료 순서가 보장되지 않는다
    • 블로킹이 발생하지 않는다
    • function func1(){
          console.log('func1');
          func2();
      }
      
      function func2(){
          setTimeout(function(){
              console.log('func2');
          }, 0);
          func3();
      }
      
      function func3(){
          console.log('func3');
      }
      func1();
      /*
      실행결과(setTimeout)
      func1
      func3
      func2
      */
      setTimeout의 콜백함수는 즉시 실행되지 않고 지정 대기 시간만큼 기다리다가 “tick” 이벤트가 발생하면 태스크 큐로 이동한 후 Call Stack이 비어졌을 때 Call Stack으로 이동되어 실행된다.

"자바스크립트는 싱글 스레드를 기반으로 동기 방식으로 작동한다."

그러나, js가 실행되는 Node.js의 libUV라이브러리 덕분에 싱글스레드임에도 여러 작업들이 동시에 비동기적으로 실행될 수 있다.

JS 엔진은 크게 2 영역으로 나뉜다.

  • Call Stack(호출 스택)
    • 작업이 요청되면 요청된 작업은 순차적으로 Call Stack에 쌓이게 되고 순차적으로 실행된다. 자바스크립트는 단 하나의 Call Stack을 사용하기 때문에 해당 task가 종료하기 전까지는 다른 어떤 task도 수행될 수 없다.
  • Heap
    • 동적으로 생성된 객체 인스턴스가 할당되는 영역이다.

이와 같이 자바스크립트 엔진은 단순히 작업이 요청되면 Call Stack을 사용하여 요청된 작업을 순차적으로 실행할 뿐이다. 앞에서 언급한 동시성(Concurrency)을 지원하기 위해 필요한 비동기 요청(이벤트를 포함) 처리는 자바스크립트 엔진을 구동하는 환경 즉 브라우저(또는 Node.js)가 담당한다.

  • Event Queue(Task Queue)
    • 비동기 처리 함수의 콜백 함수, 비동기식 이벤트 핸들러, Timer 함수(setTimeout(), setInterval())의 콜백 함수가 보관되는 영역으로 이벤트 루프(Event Loop)에 의해 특정 시점(Call Stack이 비어졌을 때)에 순차적으로 Call Stack으로 이동되어 실행된다.
  • Event Loop(이벤트 루프)
    • Call Stack 내에서 현재 실행중인 task가 있는지 그리고 Event Queue에 task가 있는지 반복하여 확인한다. 만약 Call Stack이 비어있다면 Event Queue 내의 task가 Call Stack으로 이동하고 실행된다.

Event | PoiemaWeb

 

Callback 

특정 함수에 매개변수로 전달된 함수를 의미한다. 가독성도 떨어지고 실수 위험도 커지기 때문에 es7에서는 promise,

es8에서는 async/await를 지원하여 대체한다. 

Promise

callback과 하는 일은 같으나, 작업이 끝난 후 실행할 함수를 제공하는 것이 아니라 promise 자체 메서드 .then()을 호출한다.(like 메서드 체이닝)

Async/Await

promise보다 쉽게 비동기적 상황을 표현할 수 있다.

async 선언된 함수 안에서만 awiat를 사용할 수 있다.

 

deadlock

  1. 데드락이란?
    • 둘 이상의 동시 작업이 서로 완료되기를 기다리는 경우 발생한다.
    • 두 스레드가 다른 스레드의 잠금 해제를 기다리기 때문에 서로를 영원히 차단하여 발생
  2. 발생 조건
    • 상호 배타적이어야 한다
    • 보류/대기 : 쓰레드는 다른 리소스가 오기 기다리는 동안 한 리소스를 보류
    • 선점 없음 : 스레드가 리로스를 획득한 후에 리소스에 대한 잠금을 강제로 제거할 수 없다.
    • 순환 대기 : 각 스레드는 순환 방식으로 다른 스레드에서 리로스를 기다려야 한다.
  3. 배치 처리
    • 여러개의 DB작업을 한 번에 처리하여 네트워크 오버헤드를 줄일 수 있습니다.
  4. JS에서 데드락을 방지하는 방법
    1. Thread.join()
    2. 동기화 개체 사용
    3. 중첩 잠금 방지
    4. 필요하지 않을 때 잠금을 사용하지 않는다
    5. 적절한 코드 설계

 

 

답변

가장 간단한 방법으로 로우쿼리를 작성하는 방법이 있습니다. 복잡한 쿼리는 ORM으로 처리하기 보다 로우레벨에서 처리하는 것이 성능적으로 더 좋을 수 있기 때문입니다.

그 외에도, 쿼리를 최적화 하거나 데이터나 쿼리 결과를 캐시에 캐싱하는 방법, 즉시 로딩/지연 로딩을 사용하여 N+1 쿼리 문제를 해결하거나 선택한 필드만 조회하는 프로젝션, 필요한 만큼만 데이터를 불러오는 페이지네이션 등의 방법을 사용하여 복잡한 쿼리를 쓰지 않고 데이터를 조회할 수 있습니다.