node高并发原理机制解读

 更新时间:2023年10月30日 09:54:05   作者:蛮吉(lambda)  
这篇文章主要介绍了node高并发原理机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

概念

  • 1.事件循环:

事件循环是一种编程构造,用于等待和分派程序中的事件或消息, 主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)

  • 2.事件队列:

当用户的网络请求或者其它的异步操作到来时,node都会把它放到Event Queue之中,此时并不会立即执行它,代码也不会被阻塞,继续往下走,直到主线程代码执行完毕。

  • 3.任务队列:

任务队列"是一个事件的队列(也可以理解成消息的队列),IO设备完成一项任务,就在"任务队列"中添加一个事件,表示相关的异步任务可以进入"执行栈"了。主线程读取"任务队列",就是读取里面有哪些事件。

  • 4.事件驱动:

实质是通过主循环加事件触发方式运行程序

  • 5.node

Node.js 不是一门语言也不是框架,它只是基于 Google V8 引擎的 JavaScript 运行时环境,是对 js 功能的拓展。提供了网络、文件、dns 解析、进程线程等功能。

  • 6.libuv

libuv是专门为Node.js开发的一个封装库,提供跨平台的异步I/O能力。

注:

1. 一个事件循环有一个或多个任务队列。一个任务队列是一组的任务

2. Libuv 主要是,利用系统提供的事件驱动模块解决网络异步 IO,利用线程池解决文件IO。另外还实现了定时器,对进程、线程等使用进行了封装。

node架构图

Node Standard Library 标准库,如Http, event模块。

Node Bindings 是沟通JS 和 C++的桥梁,封装V8和Libuv的细节,向上层提供基础API服务。由 C/C++ 实现。

V8 是Google开发的JavaScript引擎,提供JavaScript运行环境,可以说它就是 Node.js 的发动机。

Libuv 是专门为Node.js开发的一个封装库,提供跨平台的异步I/O能力.

单线程、异步

单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。

如果前一个任务耗时很长,后一个任务就不得不一直等着。

node单线程指的是node在执行程序代码时,主线程是单线程。

异步体现在,主线程之外,还维护了一个"事件队列"(Event queue)。

当用户的网络请求或者其它的异步操作到来时,node都会把它放到Event Queue之中,此时并不会立即执行它,代码也不会被阻塞,继续往下走,直到主线程代码执行完毕.

注:

  • JavaScript 是单线程的,Node 本身其实是多线程的,只是 I/O 线程使用的 CPU 比较少;还有个重要的观点是,除了用户的代码无法并行执行外,所有的 I/O (磁盘 I/O 和网络 I/O) 则是可以并行起来的。
  • libuv 线程池默认打开 4 个,最多打开 128个 线程。

事件循环

Node 开始执行脚本时,会先进行事件循环的初始化,但是这时事件循环还没有开始,会先完成下面的事情。

  • 同步任务
  • 发出异步请求
  • 规划定时器生效的时间
  • 执行process.nextTick()等

然后就调用libuv事件循环阶段,事件循环会无限次地执行,一轮又一轮。

只有异步任务的回调函数队列清空了,才会停止执行。

Node中的事件循环有6个阶段

event loop 的每个阶段都有一个任务队列

当 event loop 到达某个阶段时,将执行该阶段的任务队列,直到队列清空或执行的回调达到系统上限后,才会转入下一个阶段

当所有阶段被顺序执行一次后,称 event loop 完成了一个 tick

注:

node中的事件循环与浏览器有区别~

事件驱动+事件循环实现高并发

具体执行顺序:

1、每个Node.js进程只有一个主线程在执行程序代码,形成一个执行栈(execution context stack)

2、主线程之外,还维护了一个"事件队列"(Event queue)。当用户的网络请求或者其它的异步操作到来时,node都会把它放到Event Queue之中,此时并不会立即执行它,代码也不会被阻塞,继续往下走,直到主线程代码执行完毕。

3、主线程代码执行完毕完成后,然后通过Event Loop,也就是事件循环机制,开始到Event Queue的开头取出第一个事件,从线程池中分配一个线程去执行这个事件,接下来继续取出第二个事件,再从线程池中分配一个线程去执行,然后第三个,第四个。主线程不断的检查事件队列中是否有未执行的事件,直到事件队列中所有事件都执行完了,此后每当有新的事件加入到事件队列中,都会通知主线程按顺序取出交EventLoop处理。当有事件执行完毕后,会通知主线程,主线程执行回调,线程归还给线程池。

总线程不断重复第三步

注意:

我们所看到的node.js单线程只是一个js主线程与ui渲染共享一个线程,本质上的异步操作还是由线程池完成的,node将所有的阻塞操作都交给了内部的线程池去实现,本身只负责不断的往返调度,并没有进行真正的I/O操作,从而实现异步非阻塞I/O,这便是node单线程和事件驱动的精髓之处了

总结

libuv 线程池默认打开 4 个,最多打开 128个 线程。(例如:以前 web 服务器同一时间比如说最多只能接收 100 个请求,多的就无法接收了。nodejs 所谓的高并发是指可以同时接收 1000、10000 个请求,只不过以排队的方式在等待。)

主线程执行js,是单线程的,js代码在做大量计算就是cpu密集了。主线程不空闲出来也没法处理 io 的事,所以就会阻塞了。

回调只能保证某个请求按照顺序执行,不能保证多个请求访问一个资源的先后顺序,多个请求访问一个资源是要加锁的,用事务加锁就行。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

最新评论