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

Nodejs运行机制

2017-07-03-2.png
2017-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.png
1.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方式或自动重启机制解决)
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 结构思考力是这个时代所有人的必备技能,每个人几乎每时每刻都在面临着选择和决策。 如果没有结构,我们的思维就很容易从...
    Sting阅读 2,036评论 2 11
  • 今天阳光正好,心情也变好了。一扫之前的愁云惨淡,终于有力气可以面对自己的失败,自己的不足。 新年快到了,最令人愁烦...
    黄兰兰_aaa2阅读 216评论 0 0
  • 中国人的收入的算法是不一样的,如果你按工资收入,那极其低,很多大老板年收入只有几万块,那不是没钱而是都在避税。如果...
    鹭江渔夫阅读 311评论 0 0
  • 彭臻华拍摄
    彭臻华阅读 349评论 0 0