异步IO原理浅析
异步IO的好处
前端通过异步IO可以消除UI阻塞,假设请求资源A的时间为M,请求资源B的时间为N,那么同步的请求耗时为M+N,如果采用异步的方式占用时间为Max(M,N)。随着业务的复杂度提高,会引入分布式系统,时间的损耗会线性的增加,M+N+...和Max(M,N,...)还会放大同步和异步的差异。服务器资源中I/O是昂贵的,分布式I/O是更昂贵的。NodeJS适用于I/O密集型不适用于CPU密集型。
底层小知识

CPU时钟周期:
1/cpu主频 -> 1s/3.1GHz
P是并行系统中的处理器数量,f=Ws/W为串行部分的比例,s=1/f;
操作系统对计算机进行了抽象,将所有的输入输出设备抽象为文件,内核在进行文件I/O操作时,通过文件描述符进行管理,应用程序如果需要进行IO打开文件描述符,在进行文件和数量的读写,异步IO不带数据直接返回,要获取数据还需要通过文件描述符再次读取。
Node对异步IO的实现
完美的异步IO应该是应用程序发起的非阻塞的调用,无需通过遍历或者事件循环等方式轮询。
几个特殊的API
- setTimeout和setInterval线程池不参与
- process.nextTick()实现类似于setTimeout(function(){},0)每次调用放入队列中,在下一轮循环中取出。
- setImmediate()比process.nextTick()优先级低
setTimeout(function(){
console.log(1)
},0)
setImmediate(function(){
console.log(2)
})
process.nextTick(function(){
console.log(3)
})
new Promise((resolve, reject) => {
console.log(4)
resolve(4)
}).then(() => {
console.log(5)
})
console.log(6)
//4 6 3 5 1 2
sleep函数实现
async function test(){
console.log('start')
await sleep(1000)
console.log('end')
}
function sleep(ms){
return new Promise(resolve => setTimeout(resolve, ms))
}
test();
常用的Node控制异步技术手段
- step、wind(提供等待的异步库),Bigpipe、Q.js
- Async、Await
- Promise/Deffered是一种限制性异步调用,延迟传递的处理方式。Promise是高级接口,事件是低级接口,低级接口可以构建更多复杂的场景,高级接口一旦定义,不太容易改变,不再有低级接口的灵活性,但对于解决问题非常有效。
- 由于Node基于V8的原因,目前还不支持协程,协程不是进程或线程其执行过程更类似于子例程,或者说不带返回值的函数调用。
- 一个程序可以包含多个协程,可以对比与一个进程包含多个线程,多个进程相对独立有自己的上下文,切换受系统控制,而协程也相对独立有自己的上下文,但是其切换由自己控制,当前协程切换到其他协程由当前协程来控制。