单线程的Node.js是如何实现高并发的

nodejs单进程单线程事件驱动

Node遵循的是单线程单进程的模式,node的单线程是指js的引擎只有一个实例,且在nodejs的主线程中执行,同时node以事件驱动的方式处理IO等异步操作。node的单线程模式,只维持一个主线程,大大减少了线程间切换的开销,但是会有多个worker线程,用于执行异步操作。

但是node的单线程使得在主线程不能进行CPU密集型操作,否则会阻塞主线程。对于CPU密集型操作,在node中通过 child_process 可以创建独立的子进程,父子进程通过IPC通信,子进程可以是外部应用也可以是node子程序,子进程执行后可以将结果返回给父进程。

Node.js的运行机制

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

单线程的Node.js是如何实现高并发的
  • 应用层: 即 JavaScript 交互层,常见的就是 Node.js 的模块,比如 http,fs
  • V8引擎层: 即利用 V8 引擎来解析JavaScript 语法,进而和下层 API 交互
  • NodeAPI层: 为上层模块提供系统调用,一般是由 C 语言来实现,和操作系统进行交互 。
  • LIBUV层: 是跨平台的底层封装,实现了 事件循环、文件操作等,是 Node.js 实现异步的核心

Node.js 事件循环

Node.js 通常情况下是单进程的。

  • 主线程运行 V8 和 Javascript
  • 多个子线程通过 事件循环 被调度

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

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

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

事件驱动: 实质是通过主循环加事件触发方式运行程序 node Node.js 不是一门语言也不是框架,它只是基于 Google V8 引擎的 JavaScript 运行时环境,是对 js 功能的拓展。提供了网络、文件、dns 解析、进程线程等功能。

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

注意:

  1. 一个事件循环有一个或多个任务队列。一个任务队列是一组的任务
  2. Libuv 主要是,利用系统提供的事件驱动模块解决网络异步 IO,利用线程池解决文件IO。另外还实现了定时器,对进程、线程等使用进行了封装。

其实这里的事件循环和js在浏览器的事件循环是一样的,主线程允许同步代码,异步代码放到对应的工作线程中执行,回调执行结果后放进事件队列,待主线程执行事件队列的任务。

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

具体执行顺序:

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单线程和事件驱动的精髓之处了。

总结:

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

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

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

Original: https://www.cnblogs.com/axl234/p/16293687.html
Author: axl234
Title: 单线程的Node.js是如何实现高并发的

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/541742/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 奇怪的知识又增加了,ImageMagick PDF转JPG图片合并的时候报Unsupported Image Type

    之前在PDF转JPG时使用了ImageMagic这个强大的工具,起初使用都没有什么问题,但是突然生产出现部分转换后的图片合并失败的问题 报错信息: javax.imageio.II…

    Java 2023年6月7日
    090
  • CentOS7-Kibana的使用

    1.下载 Kibana官方下载​www.elastic.co 2.安装 2.1 yum安装 kibana.repo [kibana-7.x] name=Kibana reposit…

    Java 2023年6月7日
    080
  • 双指针问题的算法

    双指针主要分两类: 快慢指针和左右指针 对于 链表问题, 我们一般可以使用 快慢指针解决所谓的快慢指针是指, 使用两个指针按照不同的速度前进, 有两个指针我们可以确定: 一些题目 …

    Java 2023年6月7日
    0155
  • 自定义博客园主题

    博客园主题代码GitHub地址 https://github.com/yushixin-1024/Cnblogs-Theme-SimpleMemory 该项目Fork自https:…

    Java 2023年6月8日
    0128
  • Centos7安装jdk1.8

    创建文件夹 mkdir /usr/local/java/ 解压你的压缩包 unzip xxx.zip -d /usr/local/java/ 设置环境变量 vim /etc/pro…

    Java 2023年6月13日
    087
  • Elasticsearch性能优化汇总——写入&搜索

    在Elasticsearch的默认设置下,是综合考虑数据可靠性、搜索实时性、写入速度等因素的。当离开默认设置、追求极致的写入速度时,很多是以牺牲可靠性和搜索实时性为代价的。有时候,…

    Java 2023年6月6日
    073
  • JavaCV的摄像头实战之七:推流(带声音)

    借助JavaCV,完成本地摄像头和麦克风数据推送到媒体服务器的操作,并用VLC验证 欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://gith…

    Java 2023年6月8日
    096
  • docker 安装启动jenkins 以及问题剖析

    docker 安装启动jenkins 以及问题剖析 高考时有句”神话”,只要累不死,就往死里干。这句话依然适合现在的工作中的我们。开篇喜欢讲些小语句; 今天…

    Java 2023年6月16日
    093
  • 内存管理(二)之别小看了Tagged-Pointer关键时刻起到大作用

    本文主要研究Tagged Pointer技术,针对该技术需要解决的问题、以及在实际应用中的价值做一些简单的探讨。 如果你想要更进一步,去挖掘Tagged Pointer是如何实现的…

    Java 2023年6月16日
    068
  • fastposter发布1.5.0 跨语言的海报生成器

    fastposter发布1.5.0 跨语言的海报生成器 v1.5.0 增加右键复制、粘贴操作 fastposter低代码海报生成器,一分钟完成海报开发。支持Java,Python,…

    Java 2023年6月5日
    098
  • 对象的内存布局解析

    概念说明 Hotspot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据 (Instance Data)和对齐填充(Padding)。 * &#8…

    Java 2023年6月16日
    085
  • kotlin学习一:kotlin简介

    kotlin是JetBrains公司出品的基于JVM的语言,和其他JVM语言一样,目的在于提供比JAVA更加简介的语法, 同时提供函数式编程,不需要再像JAVA一样所有的一切都要依…

    Java 2023年6月16日
    082
  • 多线程_基础

    一.一个Java程序最少开几个线程? 3个:主线程;gc线程;异常处理线程 二.线程的生命周期以及状态? 阻塞的分类: 等待阻塞:执行wait(),需要notify()/notif…

    Java 2023年6月7日
    093
  • JBoss AS7(Application Server 7)的Standalone模式和Domain模式

    JBoss AS7(Application Server 7)支持两种引导模式:standalone和domain(域)。 Standalone模式对于很多应用,并不需要domai…

    Java 2023年6月6日
    094
  • php日志分割

    为了方便查看php错误日志信息,将php的日志按照时间进行分割,器脚本如下 phpPid =’/usr/local/webserver/php-5.3.27/var/r…

    Java 2023年6月8日
    082
  • 【LEETCODE】70、字符匹配1023 Camelcase Matching

    最近做leetcode总感觉自己是个智障,基本很少有题能自己独立做出来,都是百度。。。 不过终于还是做出了一题。。。而且速度效率还可以 哎,加油吧,尽量锤炼自己 package y…

    Java 2023年6月5日
    067
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球