深入浅出nodejs -- 异步IO,异步编程
异步 IO,异步编程
异步 IO
资源分配
一般的话会使用单线程串行一次执行,还有多线程并行完成,但是单线程串行执行,很明显速度会很慢,性能会很差,而多线程的话,可能会早场死锁以及状态的同步问题。
于是 Nodejs 采用的单线程,异步 IO,用单线程来避免死锁以及状态同步的问题,而异步的 IO,则避免了阻塞。而正对无法利用多核 CPU 的问题,Node 提供了子进程的方式来搞笑利用 CPU 和 IO。
异步 IO 与非阻塞 IO
异步和非阻塞其实是两回事。
对于操作系统对内核的 IO 来说,只有阻塞与非阻塞。
阻塞就是就是简单的所有磁盘寻道,读取数据,复制数据之后才返回。
非阻塞 IO 则是系统发出查询的请求后,请求到达之后不带数据返回,然后通过轮询的方式查看什么时候结束了再来拿取数据。
这种轮询也经历了不断地进步,从不断的发送 read;到后来 select 一次可以检查很多次,因为是数组;到后来的 poll,以链表形式突破了长度限制;到后来的 epoll,该方案是 linux 下效率最高的事件唤醒,因为他会休眠到结束,而不会一直轮询。还有 kqueue,不过这个只在 FressBSD 系统下存在。
但是注意在轮询或者休眠的状态下实际上主线程是闲置的,是利用不足的。
Linux 下有那种理想的异步 IO 方式,AIO,但是有缺陷,无法利用系统缓存。
现实中的异步 IO
其实现实中的异步 IO 是多线程的的,让部分线程来通过阻塞的或者非阻塞+轮询的形式来拿到数据,然后让一个线程进行计算处理,就实现了异步 IO。
最终的结果就是 nodejs 通过 libuv 来运行在 windows 和 linux 系统上。
注意我们时常的说 Node 是单线程的,但是其实仅仅只是 js 执行在单线程中而已,node 中,内部完成 IO 任务的其实都是另有线程池的。
非 IO 的异步 API
除了 IO 之外,还有些异步的 API,分别是 setTimeout,setInterval,setImmediate 和 process.nextTick
一般浏览器端我们想要立即异步执行一个函数,就setTimeout(function(){},0)
就行了,但是定时器需要动用红黑树,创建定时器对象和迭代,浪费性能。
process.nextTick 则是比较轻量的,直接将回调函数放入队列。
setImmediate 也是类似的,但是这个的优先级比 process.nextTick 要低,并且如果同时写两个的话,执行了一个之后,会直接进行下一轮循环
,而不是继续执行。
服务器模型
- 同步式:一次只能处理一个请求,其余的都得等待。
- 每进程/每请求:每个请求一个进程,但是扩展性不强,因为系统资源只有那么多。
- 每线程/每请求:每个请求启动一个线程,尽管线程比较轻量,但是会占内存,导致服务器缓慢。
Node 是通过事件驱动处理请求,不创建额外的对应线程。但是当大量请求来到的时候,究竟 node 发生了什么??tudo??
异步编程
高阶函数
原来高阶函数就是将函数作为参数
或者将函数作为返回值
的函数。
偏函数
就是说通过指定部分参数来产生一个新的定制函数的函数
难点
- 异常处理
异步方法通常在第一个阶段提交请求后就立即返回了,因为异常不一定发生在这个阶段,try/catch 没啥用。所以一般编写的异步函数的 callback 的第一个函数作为 err 对象,如果为 null 就代表没有错误,这其实是一种规范。
- 函数嵌套过深
当操作存在依赖关系时,我们可能会写成 callback hell,当然这个世纪问题也有很多解决办法。
- 阻塞代码
没办法像 sleep()这样的方法来将线程沉睡一下的,只能规划好代码结构调用 setTimeout 方法来做
- 多线程编程
node 无法直接利用多核的好处,但是可以使用 child_process 来解决这个问题,深层次的是 cluster 模块
异步编程解决方案
事件发布/订阅的模式
比如 node 自身提供的 events 模块,就是一个发布/订阅的模式。这个模式常常用来解耦业务,将不变的封装在组件内部,将容易变化,自定义的通过事件暴露给外部调用。
其实这种模式就是一种钩子机制,Node 很多对象都是黑盒的,通过事件钩子,可以比较清晰的看出组件的功能。
比如 HTTP 请求,我们只需要关注 error,data,end 等等事件就可以了。
NODE 对事件发布订阅做了一些额外的处理:
- 事件超过了 10 个监听器,会得到警报,因为设计者认为会出现内存泄露,调用 emitter.setMaxListeners(0)可以将限制去掉
- 为了处理异常,EventEmitter 对 error 事件进行特殊对待,如果监听了,就会交给监听器处理,否则作为异常抛出
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 981909093@qq.com
文章标题:深入浅出nodejs -- 异步IO,异步编程
文章字数:1.4k
本文作者:泽鹿
发布时间:2019-08-28, 16:45:23
最后更新:2019-08-28, 16:45:23
原始链接:http://panyifei.github.io/2019/08/28/读书笔记/深入浅出nodejs/异步IO,异步编程/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。