深入浅出nodejs读书笔记与联想
Node
node是单线程的吗?为什么?
node并非单线程,node本身还额外存在IO线程,在写c++扩展的时候会用到。node基于v8,在执行js时,是单线程的。
高并发的本质是什么?
高并发的表现是高IO,本质是提高多核CPU的利用率。再具体的讲也就是:系统内核缓冲区资源的高效利用
并发优化的软件优化方向
- cpu、内存资源、操作系统的调度优化。多核cpu与其附带内存的调度等。
- 网卡 如何充分利用多核cpu资源,或者说如何利用多核cpu分摊网卡压力
- 数据包传输(MTU)的中断对 系统资源的损耗
- 内核级别的优化:系统进程的最大连接数等
- 应用级常用数据的合理缓存(进程缓冲区与内核缓冲区的合理调度)
进程间通信的几种方法?
套接字、管道、信号量、消息队列、共享内存
为什么要用node ?
- 前后端编程语言的统一,能够提高开发信效率。
- 异步非阻塞IO能够充分利用单核性能,减少多线程模型上下文调度所耗费的资源。
- 通过事件驱动模型,提高服务端的并发能力。
- 方便前端根据需要做服务端渲染,按需分会内容等等
- 方便前端定制数据逻辑,降低前后端的沟通成本。让前后端都更能关注自己领域的问题。
node(commonjs) 模块的加载过程
- 路径分析 1. 核心模块(已被编译为二进制文件, 加载最快) 2. 带有具体路径的模块(将相对路径解析为绝对路径进行查找) 3. 第三方模块 (可通过module.path查看), 从当前路径下的 node_modules 一层层往上查找一直到根目录,若没有,继续在node全局路径一层层查找。路径较深,查找较慢。
- 文件定位 1. 优先从缓存中查找 2. 对于没有扩展名的情况,node有限匹配文件。按照 .js .json .node 的顺序依次查找,若没有匹配到文件,则尝试一层层匹配目录,若寻找到目录,则根据目录下的package.json 的main入口文件表示寻找,若没有找到,则尝试指定 index.js index.json , index.node 作为指定文件进行查找。若仍未找到,则报错。
- 编译执行 三种主要的文件类型可以被成功加载 .js 文件:会被fs模块同步加载后利用v8进行编译执行 .node 文件: c/c++扩展文件,通过dlopen() 方法加载执行 .json :通过fs模块加载后,利用JSON.parse() 进行导出 其他文件:均当做js文件加载
阻塞与非阻塞的区别?
- 阻塞IO需要等待操作系统级别的所有操作完成后,后续操作才能完成(以读取文件为例,需要经过磁盘寻址、读取数据、复制到内存中所有完成之后,其他操作才能继续执行,这期间CPU资源处于空闲)
- 阻塞IO在 执行过程中通过直接文件描述符(操作系统内核与应用程序之间的凭证)获取执行结果,无法对文件描述符进行释放;非阻塞IO,则在执行后不直接通过fd获取结果,执行结束后则再次通过fd获取执行结果, fd可以被释放。
阻塞与非阻塞都有什么优势、劣势?
- 阻塞 优势:在应用程序层面来讲,更有利于编码工作的进行,以及提高debug效率等。 劣势:无法完全利用单核CPU资源实现高并发。
- 非阻塞
优势:1. 相对于阻塞能够尽可能多得利用单核CPU的资源 2. 对于GUI层面,能够提高视觉得流畅度,例如浏览器引擎
劣势:1. 编程层面,如果没有优秀的代码组织能力,会使工程级的项目代码可读性降低,变得难以维护 2. 非阻塞的异步轮询机制也会在一定程度上浪费CPU资源。
node 是如何做到跨平台的 ?
- 在操作系统的上层添加了层平台兼容层 libuv,平台层统一的产出文件为 .node,通过执行.node文件,能够在不同平台执行c++代码,如类unix为.so,windows为.dll
什么是高可用性?
node的高可用性需要考虑什么问题?
- 多核CPU的利用
- 进程异常(父子进程)
- 内存监控与异常追踪
- 自动重启
- 多node进程负载均衡
- 缓存
- 单元测试与性能测试
如何尽可能优化node cpu的利用率 ?
- 端口监听,启动多node进程处理不同任务。
- 拆分cpu密集型业务为单个子任务
- cpu密集型业务开启子进程执行
- 在遇到大内存操作时,使用buffer或stream,避开v8引擎对堆内存的限制。
process.nextTick() 与 setImmediate() 的区别?
process.nextTick() 的回调放在数组中,每轮循环,将数组中的所有回调全部执行。setImmediate() 的回调放在一个链表中,每轮循环时,执行链表的第一个回调函数。 process.nextTick()属于idle观察者,setImmediate属于check观察者。 在一次循环检测中的优先级:idle观察者 > IO观察者 > check观察者
node 观察者模式中的:idle观察者、IO观察者、check观察者区别?
具体区别: 举例:process.nextTick()属于idle观察者,setImmediate属于check观察者。 在一次循环检测中的优先级:idle观察者 > IO观察者 > check观察者
js为何被设计成单线程?
- 首先就是为了简单快捷,主要被用作浏览器脚本语言、没有复杂的计算工作,大多为交互操作。若设计为多线程,单从上下文的切换来看就已经得不偿失。
- 其次为了解决单线程同步阻塞问题,js天然支持异步任务,可以极大程度上改善js的执行效率。
描述一下node的执行逻辑?怎样算一次事件循环?
首先js分为解析与执行两个阶段。解析阶段会对每个作用域中的变量进行声明、存储,并最终生成作用域链。 执行阶段,顺序执行逻辑代码,遇到同步任务,则进入调用栈(压栈、执行、出栈),遇到异步任务,则注册至eventTable中,当异步任务满足触发条件时,进入eventQueue, 调用栈中的同步任务执行完成后,会从eventQueue中检测是否有异步任务,如果存在,则每次取出一个异步任务到调用栈中执行,一直如此循环。具体得来讲:一次事件循环(tick)可以看做是 一次宏任务或一次微任务的执行。
- 验证一次tick:
console.log("start"); process.nextTick(() => { console.log("nextTick") }) setTimeout(() => { console.log("settimeout"); }, 0) new Promise((resolve) => { console.log("promise"); resolve() }).then(() => { process.nextTick(() => { console.log("nextTick2") }) console.log("promise then") }) console.log("end")
js中异步任务是如何执行的?
js中异步任务的执行可以看做是异步宏任务和微任务的交替执行过程。宏任务包括:整体全局同步script、setTimeout、setInterval、IO、UI交互事件、setImmediate(node);微任务包括:process.nextTick() (node)、promise
浏览器执行机制?
- 浏览器是多进程的,其中包括:browser核心进程、GUI进程、renderer进程。
- 每一个选项卡都是一个renderer进程,每一个renderer进程又是多线程的,其中包括:js引擎线程(与GUI线程互斥)、GUI线程、事件处理线程、定时器线程、http请求线程 在一个一面首次加载时,js引擎线程与GUI线程互斥共同处理页面布局,在解析HTML的过程中,首先解析DOM树(二进制、tag、node、tree),遇到js脚本与css脚本,则启动http线程加载相应的资源,此时GUI的渲染是被堵塞的,等到脚本加载完成并执行后,继续解析渲染树:解析css树、最终将dom树与css树形成渲染树。页面最终渲染后,产生的异步事件,包括交互时间、定时器事件等,则交给事件处理线程与定时器线程解决。
v8的垃圾回收机制是怎样的?
v8使用分代垃圾回收机制,根据内存的使用频率,将内存分为新生代内存与老生代内存。
- 新生代内存:Cheney垃圾回收算法:将新生代内存一分为二,每次回收,检查存活对象并复制进另一半内存中。核心思想为空间换时间,效率较高,但内存会折半。
- 老生代内存:采用mark-sweep(标记清除)为主与mark-compack(标记整理)为辅的机制
v8的内存限制?原因?
内存限制:64位系统约为1.4G,32位系统约为0.7G。 原因:可使用的内存越大,垃圾回收带来的性能损耗就会越严重,响应的滞后感就会越加明显。
js中应该多用局部变量还是全局变量?为什么?
- 从执行机制方面看,js变量寻址是按照作用域链由内层作用域向外层层寻找的,故局部变量的时间消耗更低。
- 从垃圾回收机制来看:js的局部变量使用频率较低,会被js当做新生代内存进行回收,回收效率更高。
- 从程序维护的便利性看:全局变量更容易被污染。
- 从代码可读性看:局部变量更有利于程序的阅读。 综上,在能满足开发需要的情况下,优先使用局部变量。
node 中内存泄漏的主要原因:
- 缓存:尽量使用进程外缓存,尽量不使用v8内存进行缓存,不得已时需考虑:大小限制、过期时间、更新策略
- 队列消费不及时:队列的生产速度远远大于消费速度。队列应该做最大值限制、或监控或位队列添加有效期。
- 作用域缓存未释放:闭包的滥用
node的child_process中 spawn 与 exec 的区别:
- 参数不同, spawn使用数组,exec使用字符串,exec更适合执行复杂命令。
- 返回数据的大小限制不同,exec限制为200k
- 返回数据的方式不同:spawn在子进程中一有结果数据就会返回,exec则在子进程最终执行结束后才会返回。
前端项目在做单元测试时需要注意哪些问题?
- 测试的颗粒度,单元代码的高内聚。
- 异步测试
- 超时timeout,与异常逻辑测试。
- 兼容性测试
- 接口测试
GPU加速适合什么样的场景?
- 精度低、量大、高并行计算,如图像、视频等
- 重翻Hibernate深入浅出一书,联想到威博文件管理系统的一键安装、运行
- 深入浅出Nodejs读书笔记
- 深入浅出Nodejs读书笔记
- 深入浅出Nodejs读书笔记(转)
- 深入浅出Nodejs读书笔记
- 深入浅出之正则表达式(一)
- Android绝黑剑之AutoCompleteTextView、MultiAutoCompleteTextView之智能联想
- JavaScript 深入浅出 2 运算符与表达式
- 深入浅出人脸识别原理
- 我的公司不是家 【联想员工亲历联想大裁员】
- 深入浅出的理解框架(Struts2、Hibernate、Spring)与 MVC 设计模式
- 深入浅出RxJava系列文章(大头鬼的)
- 深入浅出之正则表达式(二)转载自博客园——摩诘
- 深入浅出,camera v4l2理解(2)v4l2注册
- 联想笔记本电脑在重装系统时的设置
- 深入浅出 CopyOnWriteArrayList
- 深入浅出之正则表达式(一)
- [Cocoa]深入浅出Cocoa之多线程NSThread
- 深入浅出Mybatis系列(九)---强大的动态SQL
- 深入浅出Mysql - 优化篇(锁)