Home Articles

同步和异步编程之间有什么区别(在node.js中)

Asked
Viewed 94 times
166

我一直在阅读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') .

第一个应该是同步代码 . 第二个是异步代码 .

两件作品之间的区别对我来说非常模糊 . 输出会是什么?

谷歌搜索异步编程也没有帮助我 .

8 Answers

  • 195

    区别在于 first example ,程序将在第一行中阻塞 . 下一行( console.log )将不得不等待 .

    second example 中, 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");
    

    将会:

    • Query finished
      Next line

    • Next line
      Query finished

    注意
    虽然Node本身是 single threaded ,但有些任务可以并行运行 . 例如,文件系统操作发生在不同的进程中 .

    这就是Node可以执行异步操作的原因:一个线程正在执行文件系统操作,而主节点线程继续执行您的javascript代码 . 在像Node这样的事件驱动的服务器中,文件系统线程通知主节点线程某些事件,例如完成,失败或进度,以及与该事件相关的任何数据(例如数据库查询或错误的结果)消息)并且主节点线程决定如何处理该数据 .

    你可以在这里阅读更多相关信息:How the single threaded non blocking IO model works in Node.js

  • 63

    首先,我意识到我迟到了回答这个问题 .

    在讨论同步和异步之前,让我们简要地看看程序是如何运行的 .

    synchronous 情况下,每个语句在运行下一个语句之前完成 . 在这种情况下,程序将按语句的顺序进行精确评估 .

    这就是 asynchronous 在JavaScript中的工作方式 . JavaScript引擎中有两个部分,一部分用于查看代码并将操作排入队列,另一部分用于处理队列 . 队列处理在一个线程中发生,这就是为什么一次只能发生一个操作的原因 .

    当看到异步操作(如第二个数据库查询)时,将解析代码并将操作放入队列中,但在这种情况下,将注册回调以在此操作完成时运行 . 队列中可能已经有很多操作 . 处理队列前面的操作并从队列中删除 . 一旦处理数据库查询的操作,将请求发送到数据库,完成后将在完成时执行回调 . 此时,具有“处理”操作的队列处理器在下一操作上移动 - 在这种情况下

    console.log("Hello World");
    

    数据库查询仍在处理中,但console.log操作位于队列的前面并得到处理 . 这是一个同步操作立即执行,导致输出“Hello World” . 一段时间后,数据库操作完成,然后只调用和处理向查询注册的回调,将变量结果的值设置为行 .

    一个异步操作可能会导致另一个异步操作,第二个操作将被放入队列中,当它到达队列的前面时,它将被处理 . 调用使用异步操作注册的回调是JavaScript运行时在完成操作时返回操作结果的方式 .

    知道哪个JavaScript操作是异步的简单方法是注意它是否需要回调 - 回调是在第一个操作完成时将执行的代码 . 在问题的两个例子中,我们只能看到第二种情况有一个回调,所以它是两者的异步操作 . 情况并非总是如此,因为处理异步操作的结果的风格不同 .

    要了解更多信息,请阅读承诺 . Promise是另一种可以处理异步操作结果的方法 . 关于promises的好处是编码风格更像是同步代码 .

    许多库如节点'fs',为某些操作提供同步和异步样式 . 如果操作不需要很长时间并且没有经常使用 - 例如在读取配置文件的情况下 - 同步样式操作将导致代码更容易阅读 .

  • 20

    在同步情况下,在SQL查询完成执行之前,不会执行console.log命令 .

    在异步情况下,将直接执行console.log命令 . 然后,稍后将通过“回调”函数存储查询的结果 .

  • 17

    如果在两个示例中添加一行,这将变得更加清晰:

    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'行之前打印出来 . 在第二个(异步)示例中,result.length将(很可能)在“Hello World”行之后打印 .

    那是因为在第二个例子中, database.query 在后台异步运行,脚本继续直接与"Hello World" . console.log(result.length) 仅在数据库查询完成时执行 .

  • 5

    Sync Programming

    像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
    

    Async

    NodeJs提出异步功能,它本质上是非阻塞的,假设在任何花费时间(读取,写入,读取)的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
    

    Difference is clear where sync will definitely take more than 600 (500 + 100 + processing time) msec, async saves time.

  • 4

    这两种方法的区别如下:

    Synchronous way: 它等待每个操作完成,之后只执行下一个操作 . 对于您的查询:除非查询已完成执行以从数据库获取所有结果,否则将不会执行 console.log() 命令 .

    Asynchronous way: 它永远不会等待每个操作完成,而是仅执行第一个GO中的所有操作 . 一旦结果可用,将处理每个操作的结果 . 对于您的查询: console.log() 命令将在 Database.Query() 方法后不久执行 . 数据库查询在后台运行,并在检索完数据后加载结果 .

    Use cases

    • 如果你的操作没有像从DB中查询大量数据那么繁重,那么继续使用Synchronous方式,否则采用异步方式 .

    • 在异步方式中,您可以向用户显示一些进度指示器,而在后台,您可以继续进行重量级工作 . 这是GUI应用程序的理想方案 .

  • 2

    主要区别在于异步编程,否则不会停止执行 . 您可以在发出“请求”时继续执行其他代码 .

  • 0

    该函数使第二个异步 .

    第一个强制程序等待每一行完成它的运行,然后下一个可以继续 . 第二个允许每一行一起(并独立地)运行 .

    允许异步或并发的语言和框架(js,node.js)对于需要实时传输的事物(例如聊天,股票应用程序)非常有用 .

Related