node.js 异步编程的优点与难点笔记
node.js 原理剖析
自定义模块和核心模块相同时,自定义模块加载失败
事件驱动
基于v8引擎实现的事件驱动
大部分都继承自Event模块,简单的事件监听器模式实现,具有‘addListener/on’/once/removeLister/removeAllListener/emit/等基本的事件监听模式的方法实现
事件监听器模式也是事件钩子的机制,利用事件钩子导出内部数据或状态给外部调用者。
异步I/O原理
在操作系统中,程序运行的空间分为内核空间和用户空间。我们常常提到的异步IO,实质上是指用户空间中程序不用依赖内核空间的I/O操作完成,即可进行后续任务。
实现I/O并行
1. 多线程单进程
2. 单线程多进程
事件循环
异步I/O的必要性
node.js支持异步I/O,且是非阻塞异步处理的
阻塞与非阻塞&异步与同步
内核的特点
阻塞模式是造成应用程序等待,系统也支持非阻塞模式,这进应用程序可以在没有拿到真正数据就立即返回,为此应用程序需要多次调用才能确认I/O操作是否完全完成。
出现在应用程序中
I/O的异步与同步出现在应用程序中,如果做阻塞I/O调用,应用程序待待调用的完成过程就是一种同步状态,相反,I/O为非阻塞模式时,应用程序则是异步的。
理想状态下异步I/O
应用程序发起异步调用,不需要进行轮询,进而处理下一个任务,在I/O完成后通过信号或回调将数据传递给应用程序
window平台有一种独有的内核异步I/O方案,IOCP 应用程序 -> 异步调用方法 ->
-> 进行其它操作 执行回调并操作 <-返回<-
node.js提供的libuv作为抽象封装层,使得平台兼容性判断由这一层来判断,保证了上层的node.js 与 下层的libeio/libev(linux框架)及IOCP(windows框架)之间各自独立。node.js编译期间会判断平台条件,选择性编译unix目录及windows目录下的源文件到目标程序中。
模型如下:
Node.js -> libnuv -> widows (IOCP)
-> libev/libio
高并发策略
一般来说,高并发解决方案: 多线程模型,服务器为每个客户请求分配一个线程, 使用同步I/O, 系统切换线程来弥补同步I/O调用时间开销。
Node.js 高并发解决方案: 单线程模型,主线程处理所有请求,然后为I/O操作进行异步处理, 避开创建、销毁线程及在线程切换的开销和复杂性。
应用层 常见的是Node.js的模块 如http、fs模块-> V8引擎层(解析javascript语法,进而和下层api交互)->NodeApI层 和操作系统交互 -> LIBUV层 是跨平台底层封装,实现了事件循环、文件操作
THE NODE>JS SYSTEM
事件循环
Node.js 是 异步I/O和事件驱动,实现单线程高并发的javascript的运行时环境。
事件循环的原理
事件队列 先入先出FIFO,
入队push 尾部插入
出队shift 头部弹出
空列队 length = 0
-> 1.每个请求进行拦截,并进入处理函数(用户请求包装成event事件,event事件放到队列中,再继续接受下一个请求)
-> 2.Event Loop (底层方法)主线程方法对于I/O任务,交给线程池处理,非I/O任务,主线程处理并返回
-> 3.处理I/O任务 线程池接受到任务时,直接处理I/O操作,比如读取数据库、处理PHP程序(I/O任务),
当I/O任务完成后,就执行回调,并将事件重新放入队列中,等待循环,最后释放当前线程,当主线程再次循环到该事件,就直接处理,再执行2事件循环直接处理完成。
业务场景
不适用场景
cpu 处理密集型任务(带大量计算等)
适用场景
聊天场景