node.js에서 동기 프로그래밍과 비동기 프로그래밍의 차이점은 무엇입니까?


189

나는 nodebeginner를 읽고 있었고 다음 두 가지 코드를 보았습니다 .

첫번째:

    var result = database.query("SELECT * FROM hugetable");
    console.log("Hello World");

두 번째 것 :

    database.query("SELECT * FROM hugetable", function(rows) {
       var result = rows;
    });
    console.log("Hello World");

나는 그들이해야 할 일을 얻었고, 그들은 데이터베이스에 쿼리하여 쿼리에 대한 답변을 검색합니다. 그리고 나서 console.log('Hello world').

첫 번째는 동기 코드 일 것입니다. 두 번째는 비동기 코드입니다.

두 조각의 차이점은 매우 모호합니다. 결과물은 무엇입니까?

비동기 프로그래밍에 대한 인터넷 검색도 도움이되지 않았습니다.


41
Stange 당신은 구글에서 아무것도 찾지 못했습니다. 그것은 다소 큰 주제입니다. 동기식 프로그래밍에서 각 단계는 이전 단계가 완료된 후에 하나씩 수행됩니다. 비동기식으로 1 단계가 완료되지 않은 경우에도 2 단계가 수행됩니다. 두 번째 예제에서 정의 된 함수를 콜백 함수라고하며 데이터베이스의 결과가 반환되는 즉시 실행됩니다. 아마도 console.log가 실행 된 후에 발생합니다.
Laurent S.

7
@Bartdude 비동기 프로그래밍에는 많은 것이 있었지만 그것이 무엇인지, 그리고 그것이 실제로 무엇을 의미하는지에 대한 간단한 설명은 없습니다.
Azeirah

1
@GabrielLlamas 왜 동기 함수를 피해야합니까?
Charlie Parker

3
@CharlieParker 이벤트 루프를 차단하고 비동기 이벤트 I / O 모델의 모든 이점을 잃어 버리기 때문입니다. 그리고 그것은 나쁜 습관이기 때문입니다. 비동기식 함수를 사용하지 않는 경우 Node.js를 사용하는 이유는 무엇입니까?
Gabriel Llamas 2013

1
@GabrielLlamas, INSERT 쿼리를 실행 중이고 마지막으로 삽입 된 ID를 사용하려면 database.query()동기식으로 호출해야합니까? 또는 어떻게 접근해야합니까? (이 질문은 오랫동안 가지고 있습니다)
San

답변:


225

차이점은 첫 번째 예제 에서 프로그램이 첫 번째 라인에서 차단된다는 것입니다. 다음 줄 ( console.log)을 기다려야합니다.

에서 두 번째 예 는이 console.log질의가 처리되는 동안 실행된다. 즉, 쿼리는 백그라운드에서 처리되고 프로그램은 다른 작업을 수행하고 쿼리 데이터가 준비되면 원하는 작업을 수행합니다.

요컨대, 첫 번째 예는 차단되지만 두 번째 예는 차단되지 않습니다.

다음 두 가지 예의 출력 :

// Example 1 - Synchronous (blocks)
var result = database.query("SELECT * FROM hugetable");
console.log("Query finished");
console.log("Next line");


// Example 2 - Asynchronous (doesn't block) 
database.query("SELECT * FROM hugetable", function(result) {
    console.log("Query finished");
});
console.log("Next line");

될 것입니다 :

  1. Query finished
    Next line
  2. Next line
    Query finished

노트
노드 자체는 단일 스레드 이지만 병렬로 실행할 수있는 작업이 있습니다. 예를 들어 파일 시스템 작업은 다른 프로세스에서 발생합니다.

그렇기 때문에 Node가 비동기 작업을 수행 할 수 있습니다. 하나의 스레드는 파일 시스템 작업을 수행하고 기본 Node 스레드는 계속 자바 스크립트 코드를 실행합니다. Node와 같은 이벤트 중심 서버에서 파일 시스템 스레드는 완료, 실패 또는 진행과 같은 특정 이벤트 (예 : 데이터베이스 쿼리 결과 또는 오류와 같은 데이터)를 주 노드 스레드에 알립니다. 메시지)와 기본 노드 스레드가 해당 데이터로 수행 할 작업을 결정합니다.

여기에서 더 많은 것을 읽을 수 있습니다 : 단일 스레드 비 차단 IO 모델이 Node.js에서 작동하는 방법


9
따라서 기본적으로 첫 번째 코드를 실행하면 다음과 같은 작업이 수행됩니다. request query.; 5 seconds later when the request is done; console.log; 두 번째 것이 실행될 때 : request query; console.log; work on the query;
Azeirah

1
@JohnGalt SQL은 다른 스레드에서 실행됩니다. 그러나 물론 그것은 사용하는 SQL 드라이버의 구현에 달려 있습니다. 드라이버는 새 스레드를 생성하고 mysql에 연결 한 다음 쿼리를 실행해야합니다. 완료되면 결과를 이벤트 큐에 게시하면 노드가 콜백을 호출합니다.
Salvatorelab

4
비동기 예제가 # 1과 동일한 것을 출력 할 수 없습니까? 예를 들어, database.query너무 빨리 마무리되어 우리 console.log가 작업에 도달 할 때까지 이미 완료되었습니다.
greatwolf

2
@TheBronx console.log("Next line");예제 2에서 익명 함수 안에 있다면 바로 console.log("query finished");다음에 "쿼리 완료"후에 "다음 줄"이 인쇄 될 것입니까? 따라서 모든 것이 중첩 된 방식으로 있으면 모든 것이 동기 방식으로 실행되므로 특정 기능의 동기 버전 사용에 대해 걱정할 필요가 없습니다. 이해가 정확합니까?
Abdul

4
짧은 대답 : 예 @Abdul, 당신 말이 맞아요. 긴 답변 : 중첩 함수 (콜백)는 "서로"순차적으로 작업을 수행하는 방법입니다. 그러나 그것은 기술적으로 "동기"가 아닙니다. 익명 기능은 여전히 ​​"차단 작업이 완료된 경우"또는 다른 말로 "비동기"로 실행됩니다. 차단 작업이 진행되는 동안 Node.js가 다른 기능을 실행할 수 있습니다. 함수는 체인을 유지하는 것만으로 비동기 상태를 유지합니다. 동기화 기능은 실행을 차단합니다. 이것이 바로 핵심입니다.
Salvatorelab

75

이 두 가지 방법의 차이점은 다음과 같습니다.

동기 방식 : 각 작업이 완료 될 때까지 기다린 후 다음 작업 만 실행합니다. 쿼리의 경우 : console.log()데이터베이스에서 모든 결과를 얻기 위해 쿼리 실행이 완료되지 않는 한 &가 될 때까지 명령이 실행되지 않습니다.

비동기 방식 : 각 작업이 완료 될 때까지 기다리지 않고 첫 번째 GO에서만 모든 작업을 실행합니다. 결과가 나오면 각 작업의 결과가 처리됩니다. 쿼리의 경우 : 메소드 console.log()실행 후 명령이 곧 실행됩니다 Database.Query(). 데이터베이스 쿼리는 백그라운드에서 실행되고 데이터 검색이 완료되면 결과를로드합니다.

사용 사례

  1. DB에서 대량의 데이터를 쿼리하는 것과 같이 작업이 너무 많이 들리지 않으면 동기 방식으로 진행하고 그렇지 않으면 비동기 방식으로 진행하십시오.

  2. 비동기 방식으로 사용자에게 일부 진행 표시기를 표시 할 수 있으며 백그라운드에서 무거운 작업을 계속할 수 있습니다. 이것은 GUI 앱에 이상적인 시나리오입니다.


2
이는 db.query (cmd, callback)가 동시에 스레드에서 실행되고 있음을 의미합니까? 그들은 동시에 달리고 있습니까?
Charlie Parker

그의 두 번째 예에서는 쿼리가 너무 빨리 끝나서 콜백을 먼저 호출 할 가능성이 console.log있습니까?
Fahmi

@Fahmi 이론적 네, 실제로 아주 불가능
레오 메시

24

두 예제 모두에 줄을 추가하면 조금 더 명확 해집니다.

var result = database.query("SELECT * FROM hugetable");
console.log(result.length);
console.log("Hello World");

두 번째 것 :

database.query("SELECT * FROM hugetable", function(rows) {
   var result = rows;
   console.log(result.length);
});
console.log("Hello World");

이것을 실행하면 첫 번째 (동기식) 예제 인 result.length가 'Hello World'행 전에 인쇄됩니다. 두 번째 (비동기식) 예제에서는 "Hello World"행 뒤에 result.length가 인쇄 될 가능성이 높습니다.

두 번째 예에서는 database.query백그라운드에서 비동기식으로 실행되고 스크립트는 "Hello World"와 함께 계속 진행 되기 때문입니다 . 는 console.log(result.length)데이터베이스 쿼리가 완료된 경우에만 실행됩니다.


1
"Hello World"행 뒤에 result.length가 인쇄 될 것 입니다. .... 왜 "가장 가능성이 높을까요"? 나는 항상 console.log 출력 후에 인쇄된다고 생각합니다. 설명을 주셔서 감사합니다 :)
humanANDANDpeace

9
@humanityANDpeace : 이것이 비동기 액세스의 전체 요점입니다. 언제 수행되는지 알 수 없습니다 . 아마도 그것은 엄청나게 빠른 데이터베이스이고, 자바 스크립트가 "Hello World"라인에 도달하기 전에도 데이터베이스 쿼리가 반환됩니다.
Martijn

19

먼저, 나는이 질문에 대답하는데 늦었다는 것을 알고 있습니다.

동기식 및 비동기식에 대해 논의하기 전에 프로그램 실행 방법을 간단히 살펴 보겠습니다.

에서 동기 의 경우, 각 문 완료 다음 명령문이 실행되기 전에. 이 경우 프로그램은 명령문 순서대로 정확하게 평가됩니다.

이것은 비동기식입니다 JavaScript에서 방식입니다. JavaScript 엔진에는 코드를 확인하고 작업을 대기열에 넣는 부분과 대기열을 처리하는 부분이 있습니다. 큐 처리는 하나의 스레드에서 발생하므로 한 번에 하나의 작업 만 발생할 수 있습니다.

두 번째 데이터베이스 쿼리와 같은 비동기 작업이 표시되면 코드가 구문 분석되고 작업이 대기열에 배치되지만이 경우이 작업이 완료되면 콜백이 실행되도록 등록됩니다. 대기열에 이미 많은 작업이있을 수 있습니다. 큐 앞의 조작이 처리되고 큐에서 제거됩니다. 데이터베이스 쿼리 작업이 처리되면 요청이 데이터베이스로 전송되고 완료되면 콜백이 완료시 실행됩니다. 이때 작업을 "처리 한"큐 프로세서는 다음 작업에서 이동합니다.이 경우

    console.log("Hello World"); 

데이터베이스 쿼리가 여전히 처리되고 있지만 console.log 작업이 큐의 앞에 있으며 처리됩니다. 이것은 동기 작업이므로 즉시 "Hello World"출력이 생성됩니다. 얼마 후, 데이터베이스 작업이 완료된 후에 만 ​​쿼리에 등록 된 콜백이 호출되고 처리되어 변수 결과 값이 행으로 설정됩니다.

하나의 비동기 작업으로 인해 다른 비동기 작업이 발생할 수 있습니다.이 두 번째 작업은 큐에 배치되고 큐의 맨 앞에 오면 처리됩니다. 비동기 작업으로 등록 된 콜백을 호출하면 JavaScript 런타임이 작업 수행시 작업 결과를 반환하는 방식입니다.

어떤 JavaScript 작업이 비동기인지 알 수있는 간단한 방법은 콜백이 필요한지 확인하는 것입니다. 콜백은 첫 번째 작업이 완료 될 때 실행될 코드입니다. 문제의 두 가지 예에서 두 번째 경우에만 콜백이 있음을 알 수 있으므로 두 경우의 비동기 작업입니다. 비동기 작업의 결과를 처리하는 스타일이 다르기 때문에 항상 그런 것은 아닙니다.

자세한 내용은 약속에 대해 읽으십시오. 약속은 비동기 작업의 결과를 처리 할 수있는 또 다른 방법입니다. 약속에 대한 좋은 점은 코딩 스타일이 동기 코드와 비슷하다는 느낌입니다.

노드 'fs'와 같은 많은 라이브러리는 일부 작업에 동기식 스타일과 비동기식 스타일을 모두 제공합니다. 구성 파일을 읽는 경우와 같이 작업 시간이 오래 걸리고 많이 사용되지 않는 경우 동기 스타일 작업을 수행하면 코드를보다 쉽게 ​​읽을 수 있습니다.


6

동 기적 경우 SQL 쿼리 실행이 완료 될 때까지 console.log 명령이 실행되지 않습니다.

비동기적인 경우 console.log 명령이 직접 실행됩니다. 쿼리 결과는 나중에 "콜백"기능에 의해 저장됩니다.


1
그러나 실제로 동시에 호출되고 있습니까? 나를 혼란스럽게하는 것은 비동기 코드에서 실제 코드가 동시에 실행되고 있습니까?
Charlie Parker

이것은 프로세서 (멀티 코어입니까?) 및 운영 체제에 따라 다릅니다. 참조 en.wikipedia.org/wiki/Multithreading_(software)#Multithreading은
관련

4

주요 차이점은 비동기 프로그래밍과 달리 실행을 중지하지 않습니다. '요청'이 진행되는 동안 다른 코드를 계속 실행할 수 있습니다.


2

이 함수는 두 번째 것을 비동기로 만듭니다.

첫 번째는 프로그램이 다음 행을 계속하기 전에 각 행의 실행이 끝날 때까지 프로그램이 강제로 실행하도록합니다. 두 번째 줄은 각 줄을 한 번에 함께 (그리고 독립적으로) 실행할 수 있습니다.

비동기식 또는 동시성을 허용하는 언어 및 프레임 워크 (js, node.js)는 실시간 전송 (예 : 채팅, 스톡 애플리케이션)이 필요한 작업에 적합합니다.


0

동기화 프로그래밍

C, C #, Java와 같은 프로그래밍 언어는 동기화 프로그래밍이므로, 작성한 순서대로 작성됩니다.

-GET DATA FROM SQL.
//Suppose fetching data take 500 msec

-PERFORM SOME OTHER FUNCTION.
//Performing some function other will take 100 msec, but execution of other 
//task start only when fetching of sql data done (i.e some other function 
//can execute only after first in process job finishes).

-TOTAL TIME OF EXECUTION IS ALWAYS GREATER THAN (500 + 100 + processing time) 
msec

비동기

NodeJ는 비동기 기능을 제공하며 본질적으로 블로킹이 아니며 시간이 걸리는 I / O 작업 (가져 오기, 쓰기, 읽기), nodejs가 유휴 상태로 유지되지 않고 작업이 완료 될 때까지 기다린다고 가정하십시오. 대기열에서 다음 작업을 실행하기 시작하고, 작업이 완료 될 때마다 콜백을 사용하여 알립니다. 다음 예제가 도움이 될 것입니다.

//Nodejs uses callback pattern to describe functions.
//Please read callback pattern to understand this example

//Suppose following function (I/O involved) took 500 msec
function timeConsumingFunction(params, callback){
  //GET DATA FROM SQL
  getDataFromSql(params, function(error, results){
    if(error){
      callback(error);
    }
    else{
      callback(null, results);
    }
  })
}

//Suppose following function is non-blocking and took 100 msec
function someOtherTask(){
  //some other task
  console.log('Some Task 1');
  console.log('Some Task 2');
}

console.log('Execution Start');

//Start With this function
timeConsumingFunction(params, function(error, results){
    if(error){
      console.log('Error')
    }
    else{
      console.log('Successfull'); 
    }
  })

//As (suppose) timeConsumingFunction took 500 msec, 
//As NodeJs is non-blocking, rather than remain idle for 500 msec, it will start 
//execute following function immediately
someOtherTask();

간단히 말해 출력은 다음과 같습니다.

Execution Start
//Roughly after 105 msec (5 msec it'll take in processing)
Some Task 1
Some Task 2
//Roughly After 510 msec
Error/Successful //depends on success and failure of DB function execution

동기화가 600 (500 + 100 + 처리 시간) msec 이상을 확실히 차지하는 위치의 차이가 분명하여 비동기 시간이 절약됩니다.


0

비동기 기능은 차단하는 동안 동기 기능은 차단됩니다. 동기 함수에서 명령문은 다음 명령문이 실행되기 전에 완료됩니다. 이 경우, 프로그램은 명령문 순서대로 정확하게 평가되며 명령문 중 하나가 매우 오래 걸리면 프로그램 실행이 일시 정지됩니다.

비동기 함수는 일반적으로 콜백을 매개 변수로 받아들이고 비동기 함수가 호출 된 직후 다음 줄에서 실행이 계속됩니다. 콜백은 비동기 작업이 완료되고 콜 스택이 비어있는 경우에만 호출됩니다. 웹 서버에서 데이터를로드하거나 데이터베이스를 쿼리하는 등의 무거운 작업은 비동기 적으로 수행되어야 긴 스레드 작업이 완료 될 때까지 메인 스레드가 차단하는 대신 다른 작업을 계속 실행할 수 있습니다 (브라우저의 경우 UI가 정지됨) .

원래 Github에 게시 : 링크


0

JS의 비동기 프로그래밍 :

동기식

  • 완료 될 때까지 추가 코드의 실행을 중지합니다.
  • 추가 실행이 중단되기 때문에 동기 코드를 '블로킹'이라고합니다. 다른 코드는 실행되지 않습니다.

비동기

  • 이것의 실행은 이벤트 루프로 연기되며, 이것은 비동기 함수를 실행하는 JS 가상 머신의 구조입니다 (동기 함수의 스택이 비어있는 후).
  • 비동기 코드는 추가 코드 실행을 차단하지 않기 때문에 비 블로킹이라고합니다.

예:

// This function is synchronous
function log(arg) {
    console.log(arg)
}

log(1);

// This function is asynchronous
setTimeout(() => {
    console.log(2)
}, 0);

log(3)

  • 이 예는 1, 3, 2를 기록합니다.
  • 2는 스택이 비운 후에 실행되는 비동기 함수 내에 있기 때문에 마지막에 기록됩니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.