极简 Node.js 入门 - Node.js 是什么、性能有优势?
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node
本文更佳阅读体验:https://www.yuque.com/sunluyong/node/what-is-node
定义
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine.
现在 Node.js 官网的定义就这么简单,但也可以看出几个最重要的特征
- Node.js 不是一门语言,是一个运行时,和浏览器更像,只不过运行在服务端
- 这个运行时的方言是 JavaScript(不包含 BOM、DOM API,增加了 Stream、网络等 API)
- Node.js 是靠 Chrome V8 引擎运行 JavaScript
对应到 Java 我们可以理解 Node.js 是 JDK,装上就能在服务端跑 JavaScript 代码了。
Chrome 和 Node.js 同样是 JavaScript 运行时,都使用了 V8 引擎,主要区别在于 V8 只实现了 ECMAScript 的数据类型、对象和方法,Chrome 运行时提供了 Window、DOM、BOM,而 Node.js 运行时提供了global、 Buffer、net 等模块
下面内容需要一些计算机基础知识,但看不懂并不影响 Node.js 的学习
事件驱动 & 非阻塞 I/O 是什么
在 Node.js 才诞生的时候大家总是充满了好奇,早期官网上的介绍要更多一些,主要说了 Node 最核心的两个特性:事件驱动、非阻塞 I/O
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node.js' package ecosystem, npm, is the largest ecosystem of open source libraries in the world.
举个例子理解 Node.js 和之前大部分 web 应用编程区别,当读取数据库的时候会写出这样的代码
var result = db.query('select * from...');
I/O 是一个相对耗时较长的工作(这是后面讨论的前提),I/O 任务主要由 CPU 分发给 DMA 执行,等待数据库查询结果的时候进程在做什么?大部分时候就是单纯在等着而已
不同硬件设备 I/O 操作所花费 CPU cycles
Action Cost (CPU cycles)
L1 Cache* 3
L2 Cache* 14
RAM* 250
Disk 41,000,000
Network 240,000,000
这明显是在浪费 CPU,所以有了多线程的性能优化手段,但学习操作系统的时候我们就知道
- 操作系统创建线程和切换多和线程上下文需要一定的开销
- 因为多线程带来的执行堆栈是要占用内存的
- 多线程变成面对的死锁、状态同步等问题会增加使用的复杂性
上面的代码要么阻塞整个进程,要么使用了多线程,如果进程不等待 I/O 结果,直接处理后续任务就是非阻塞 I/O,这样可以不用浪费 CPU
db.query('select * from...', function (result) {
// 消费 result
});
在 Promise、async|await 没有的年代,回调是异步的通用处理方式
进程如何获知异步 I/O 调用完成,触发回调函数呢?这就要靠 Event Loop 实现,也就是上面提到的事件驱动
这个图看起来非常复杂,有几个要点可以帮助理解
- 在 Node.js 中所有操作称之为事件,客户端的请求也是事件,所有事件维护在图中最左侧的事件队列中
- Node.js 主线程也就是图中间的循环就是 Event Loop,主要作用是轮训事件队列中是否存在事件
- 有非阻塞事件,按照先进先出原则依次调用处理
- 有阻塞事件,交给图中最右侧的 C++ 线程池处理,线程池处理完成后把结果通过 Event Loop 返回给事件队列
- 进行下一次循环
- 一个请求所有事件都被处理,把响应结果发给客户端,完成一次请求
这样一个请求 - 响应模型就完成了,如果在 Event Loop 中包含同步的 CPU 密集操作,就会阻塞主线程
Node.js 性能真的高吗?
要回答这个问题首先需要了解几个基本常识
- CPU 运算远远快于 I/O 操作
- Web 是典型的 I/O 密集场景
- JavaScript 是单线程,但 JavaScript 的 runtime Node.js 并不是,负责 Event Loop 的 libuv 用 C 和 C++ 编写
很多语言是依赖的多线程解决高并发,一个线程处理一条用户请求,处理完成了释放线程,在阻塞 I/O 模型下, I/O 期间该用户线程所占用的 CPU 资源(虽然十分微量,大部分交给了 DMA)什么都不做,等待 I/O,然后响应用户,而且开启多个进程/线程 CPU 切换 Context 的时间也十分可观
就像饭店的服务员只负责点菜,如果给每个厨师都配一个服务员,服务员把客人菜单给大厨后就玩手机等着一样,你是老板你也生气,况且不同于饭店大厨工资高于服务员,在计算机世界,CPU 资源比 I/O 宝贵的多
说 Node.js 在高并发、I/O 密集场景性能高,也就是 Web 场景性能高主要也是解决这个问题,没必要一个厨师配一个服务员,整个饭店说不定一个服务员就够了,剩下的钱可以随便做其它事情
用户请求来了, CPU 的部分做完不用等待 I/O,交给底层完成,然后可以接着处理下一个请求了,快就快在
- 非阻塞 I/O
- Web 场景 I/O 密集
- 没多线程 Context 切换开销,多出来的开销是维护 EventLoop
其它场景 NodeJS 性能确实不高,甚至非常低下,感兴趣可以看一下 Apache(多进程) 和 Nginx(事件驱动) 对比,现在大型 web 应用普遍是 Nginx 在最前面做负载均衡服务器、静态资源服务器,Apache 在下一层做实际 Web Server,响应动态请求
因此 Node.js 在 I/O 密集的 Web 场景相对于使用多进程模型语言有性能优势,这个优势不是来源于语言,而是操作系统实现,Java 按照这种模型实现性能一样很高
得益于 V8 的优化和 C/C++ 拓展,Node.js 执行 CPU 密集任务性能并不差,但如果长时间进行 CPU 运算会阻塞后续 I/O 任务发起,用 Java 实现非阻塞模型也会遇到一样问题
参考
- Node.js 作者 Ryan Dahl 介绍 Node.jsRyan Dahl 2009 JSconf - Node.js.pdf
- NGINX 如何实现高性能和可扩展性
- 深入理解 JavaScript Event Loop
极简 Node.js 入门 - Node.js 是什么、性能有优势?的更多相关文章
- Node.js入门-Node.js 介绍
Node.js 是什么 Node.js 不是一种独立的语言,与 PHP,Python 等"既是语言优势平台"不同,它也不是一个 JavaScrip 框架,不同于 CakePHP,D ...
- Vue.js 入门 --- vue.js 安装
本博文转载 https://blog.csdn.net/m0_37479246/article/details/78836686 Vue.js(读音 /vjuː/, 类似于 view)是一个构建数据 ...
- js入门 关于js属性及其数据类型(详解)
1. js的本质就是处理数据.数据来自于后台的数据库. 所以变量就起到一个临时存储数据的作用. ECMAScript制定了js的数据类型. 数据类型有哪些? 1. 字符串 String 2. 数字 ...
- js入门关于js‘i++’‘++i’和‘i--’‘--i’计算的问题
一,i++和++i; i++是先赋值在运算,++i是先运算在赋值: 例如:var a=1 a++:在运算时是按照1计算的:但在下面再次出现时是按照2进行运算: ++a:在运算时是按照2计算的:在下面再 ...
- 极简 Node.js 入门 - 1.2 模块系统
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
- 极简 Node.js 入门 - 1.3 调试
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
- 极简 Node.js 入门 - 1.4 NPM & package.json
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
- 极简 Node.js 入门 - 2.1 Path
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
- 极简 Node.js 入门 - 2.2 事件
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
随机推荐
- 记一次在Grafana中使用Worldmap Panel的经历
背景 因与工作相关,以下内容皆做了脱敏处理 主要的需求是要根据地理位置查看可视化的数据. 安装及创建 安装命令来源于官网 grafana-cli plugins install grafana-wor ...
- python3 读取chrome浏览器cookies
原文链接:https://www.cnblogs.com/gayhub/p/pythongetcookiefromchrome.html 好几年前我在做一些自动化的脚本时,脑子里也闪过这样的想法:能不 ...
- 数据可视化之DAX篇(二十三)ALLEXCEPT应用示例:更灵活的累计求和
https://zhuanlan.zhihu.com/p/67441847 累计求和问题,之前已经介绍过(有了这几个公式,你也可以快速搞定累计求和),主要是基于比较简单的情形,针对所有的数据进行累计求 ...
- 《重学 Java 设计模式》PDF 出炉了 - 小傅哥,肝了50天写出18万字271页的实战编程资料
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! @ 目录 一.前言 二.简介 1. 谁发明了设计模式? 2. 我怎么学不会设计模式? 3. 适 ...
- JavaScript 基础 学习(三)
JavaScript 基础 学习(三) 事件三要素 1.事件源: 绑定在谁身上的事件(和谁约定好) 2.事件类型: 绑定一个什么事件 3.事件处理函数: 当行为发生的时候,要执行哪一个函数 ...
- MVC + EFCore 项目实战 - 数仓管理系统5 – 菜单配置及里程碑划分
上次课程我们完成了需求的梳理. 我们根据梳理的需求把菜单配好,另外我们把项目里程碑也配置在系统中,开发和管理都在系统中,形成无文档化管理. 一.菜单配置 根据我们的归纳图,我们先将菜单配置好. 我们遵 ...
- RocketMQ在面试中那些常见问题及答案+汇总
0.汇总 RocketMQ入门到入土(一)新手也能看懂的原理和实战! RocketMQ入门到入土(二)事务消息&顺序消息 从入门到入土(三)RocketMQ 怎么保证的消息不丢失? Rocke ...
- JVM——内存区域:运行时数据区域详解
关注微信公众号:CodingTechWork,一起学习进步. 引言 我们经常会被问到一个问题是Java和C++有何区别?我们除了能回答一个是面向对象.一个是面向过程编程以外,我们还会从底层内存管理 ...
- jmeter 及测试(转载)
负载测试:在一定的工作负荷下,给系统造成的负荷及系统响应的时间. 压力测试:在一定的负荷条件下,长时间连续运行系统给系统性能造成的影响. 1.性能测试(Performance Test):通常收集 ...
- .Net微服务实战之负载均衡(上)
系列文章 .Net微服务实战之技术选型篇 .Net微服务实战之技术架构分层篇 .Net微服务实战之DevOps篇 相关源码:https://github.com/SkyChenSky/Sikiro P ...