美文网首页Web Developer大前端从入门到跑路
Nodejs单线程为什么能支持高并发?

Nodejs单线程为什么能支持高并发?

作者: 方寸拾光 | 来源:发表于2019-04-09 13:23 被阅读0次

    Nodejs运行机制

    2017-07-03-2.png2017-07-03-2.png
    1. V8引擎解析JavaScript脚本
    2. 解析后的代码,调用Node API
    3. libuv库负责Node API的执行。它将不同的任务分配给不同的线程,形成一个Event Loop(事件循环),以异步的方式将任务的执行结果返回给V8引擎
    4. V8引擎再将结果返回给用户

    Node.js的单线程指的是主线程是“单线程”,由主要线程去按照编码顺序一步步执行程序代码,假如遇到同步代码阻塞,主线程被占用,后续的程序代码执行就会被卡住。实践一个测试代码:

    const http = require('http');
    function sleep(time) {    
      const _exit = Date.now() + time * 1000;    
      while( Date.now() < _exit ) {}    
      return ;
    }
    const server = http.createServer(function(req, res){
        sleep(10);
        res.end('server sleep 10s');
    });
    
    server.listen(8080);
    

    先将index.js的代码改成这样,然后打开浏览器,你会发现浏览器在10秒之后才做出反应,打出Hello Node.js。

    这是主线程时序图:

    JavaScript是解析性语言,代码按照编码顺序一行一行被压进stack里面执行,执行完成后移除然后继续压下一行代码块进去执行。上面代码块的堆栈图,当主线程接受了request后,程序被压进同步执行的sleep执行块(我们假设这里就是程序的业务处理),如果在这10s内有第二个request进来就会被压进stack里面等待10s执行完成后再进一步处理下一个请求,后面的请求都会被挂起等待前面的同步执行完成后再执行。

    那么我们会疑问:为什么一个单线程的效率可以这么高,同时处理数万级的并发而不会造成阻塞呢?就是我们下面所说的--------事件驱动。

    事件驱动/事件循环/线程池

    1.png1.png
    1. 每个Node.js进程只有一个主线程在执行程序代码,形成一个执行栈execution context stack)。
    2. 主线程之外,还维护了一个"事件队列"(Event queue)。当用户的网络请求或者其它的异步操作到来时,node都会把它放到Event Queue之中,此时并不会立即执行它,代码也不会被阻塞,继续往下走,直到主线程代码执行完毕。
    3. 主线程代码执行完毕完成后,然后通过Event Loop,也就是事件循环机制,开始到Event Queue的开头取出第一个事件,从线程池中分配一个线程去执行这个事件,接下来继续取出第二个事件,再从线程池中分配一个线程去执行,然后第三个,第四个。主线程不断的检查事件队列中是否有未执行的事件,直到事件队列中所有事件都执行完了,此后每当有新的事件加入到事件队列中,都会通知主线程按顺序取出交EventLoop处理。当有事件执行完毕后,会通知主线程,主线程执行回调,线程归还给线程池。
    4. 主线程不断重复上面的第三步。

    单线程的好处:

    • 多线程占用内存高
    • 多线程间切换使得CPU开销大
    • 多线程由内存同步开销
    • 编写单线程程序简单
    • 线程安全

    单线程的劣势:

    • CPU密集型任务占用CPU时间长(可通过cluster方式解决)
    • 无法利用CPU的多核(可通过cluster方式解决)
    • 单线程抛出异常使得程序停止(可通过try catch方式或自动重启机制解决)

    相关文章

      网友评论

        本文标题:Nodejs单线程为什么能支持高并发?

        本文链接:https://www.haomeiwen.com/subject/dxebiqtx.html