zoukankan      html  css  js  c++  java
  • Node 初探异步编程

    从C/C++转过来最开始不适应的就是这个了吧。=-=

    Node是单线程,那么怎么提高效率?怎么解决一些阻塞问题?Node的基因里使用了异步IO,上次在http://www.cnblogs.com/zhangmingzhao/p/7564738.html 已经说到这个问题,Node的异步机制往往伴随着回调。

    先看一个关于CPU的例子来比较同步和异步:

       同步:CPU需要计算10个数据,每计算一个结果后,将其写入磁盘,等待写入成功后,再计算下一个数据,直到完成。

       异步:CPU需要计算10个数据,每计算一个结果后,将其写入磁盘,不等待写入成功与否的结果,立刻返回继续计算下一个数据,计算过程中可以收到之前写入是否成功的通知,直到完成。

    如过没有异步,CPU写入磁盘等待返回的结果的等待时间也被无情的消耗了。来看一段代码:

    我们期待的结果是1,但是结果确实0。为什么呢?

    这个就是node的异步机制。我们先执行了plus,没有等2秒,而是直接运行下一句打印函数,此时的c值还是0.

    那怎么解决这个问题呢?

    传入回调函数来解决。

    我们来给plus传入一个callback函数,如下:

    运行结果,打印出1。

    由于异步的高效性,node.js设计之初就考虑做为一个高效的web服务器,作者理所当然地使用了异步机制,并贯穿于整个node.js的编程模型中,新手在使用node.js编程时,往往会羁绊于由于其他编程语言的习惯,比如C/C++,觉得无所适从。我们可以从以下一段简单的睡眠程序代码窥视出他们的区别。

    我们来写一个Java的:

    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class Main {
        public static void main(String[] args) {
            int i;
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
            for(i = 0; i < 10; i++) {
                System.out.println(df.format(new Date()));
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    运用Java中线程的sleep来得到如下结果:

    2017-09-22 18:53:41
    2017-09-22 18:53:43
    2017-09-22 18:53:45
    2017-09-22 18:53:47
    2017-09-22 18:53:49
    2017-09-22 18:53:51
    2017-09-22 18:53:53
    2017-09-22 18:53:55
    2017-09-22 18:53:57
    2017-09-22 18:53:59

    我们把代码直译成Node版本:

    function test() {
        for (var i = 0; i < 10; i++) {
            console.log(new Date);
            setTimeout(function(){}, 2000);    //睡眠2秒,然后再进行一下次for循环打印
        }
    };
    test();

    我们发现这个结果几乎是同时打印出来,2秒并没有起到什么作用。

    setTimeout的第二个参数表示该时间之后在执行第一个参数表示的callback函数。

    因此我们可以分析, 由于Node.js的异步机制,setTimeout每个for循环到此之后,都注册了一个2秒后执行的回调函数然后立即返回马上执行console.log(new Date),导致了所有打印的时间都是同一个点。然而这个函数仅仅是注册,空函数什么事都没做。那么我这样呢:

    for (var i = 0; i < 10; i++) {
        setTimeout(function() {
            console.log(new Date);
        }, 2000);
    }

    结果是等了2秒后,一下子打印了10个

    还是异步特性,我们可以这样理解,for循环里每次setTimeout注册了2秒之后执行的一个打印时间的回调函数,没有等2秒,而是立即返回,再执行setTimeout,如此反复直到for循环结束,因为执行速度太快,导致同一个时间点注册了10个2秒后执行的回调函数,然后for循环结束,因此导致了2秒后所有回调函数的立即执行。 

     继续测试,我们加上 console.log("before FOR: " + new Date)和之后console.log("after FOR: " + new Date)

    console.log("before FOR: " + new Date)
    for (var i = 0; i < 10; i++) {
        setTimeout(function() {
            console.log(new Date);
        }, 2000);
    }
    console.log("after FOR: " + new Date)

    这个与一开始的例子差不多,中间的延迟不影响下面代码的运行。

    before和after几乎在同一时刻运行

    而定时器中的回调函数则按要求的2秒之后执行,也是同一秒内执行完毕。那么如何实现最初Java语言每隔2秒打印一个系统时间的需求函数呢,这样写,结果也可以达到要求:

    function test() {
        for (var i = 0; i < 10; i++) {
            console.log(new Date);
            wsleep(2000);    //睡眠2秒,然后再进行一下次for循环打印
        }
    };
    test();
    
    function wsleep(milliSecond) {
        var startTime = new Date().getTime();
        while(new Date().getTime() <= milliSecond + startTime) {
        }
    }

    但是在实际情况中是不会这么写的,这样阻塞了CPU20s的时间,而不能干其他事,异步的存在就是提高效率。

    还有这样写可能会更帮助理解:

    for (var i = 0; i < 10; i++) {
        setTimeout(function () {
            console.log(new Date());
        }, 2000*(i+1));
    }

    我们发现打印的都是结果i为0时注册的函数。

  • 相关阅读:
    mybatis 错误 Invalid bound statement (not found)
    Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.
    bug 记录 Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans
    解决:The Tomcat connector configured to listen on port 8182 failed to start. The port may already be in use or the connector may be misconfigured.
    jquery validate 验证插件 解决多个相同的Name 只验证第一个的方案
    phpStorm+xdebug调试(php7.3)
    小程序视频多个视频播放与暂停
    CSS实现单行、多行文本溢出显示省略号(…)
    Packet for query is too large (4,544,730 > 4,194,304). You can change this value on the server by setting the 'max_allowed_packet' variable.
    idea自动在文件头中添加作者和创建时间
  • 原文地址:https://www.cnblogs.com/zhangmingzhao/p/7577135.html
Copyright © 2011-2022 走看看