要搞清楚NodeJs的异步I/O,首先要知道以下的几点。
NodeJs单线程
单线程其实就是按从上到下顺序依次来执行,而且每次只执行一个任务,只有当前这个任务执行完了,才会执行下一个任务。
这里有个误区,Node自然其实是多线程的。只是解析和执行JavaScript代码的线程只有一个,即主线程。这就是NodeJs为何是单线程的原因了。但实际上还有其他的线程:处理AJAX请求的线程、处理DOM事件的线程、定时器线程、读写文件的线程等。这些线程称为工作线程,类似Web Workers的方式来接近JavaScript大计算阻塞UI渲染的问题。
事件驱动
事件驱动编程主要思想是通过事件或状态的变化来进行应用程序的流程控制,一般通过事件监听完成,一旦事件被检测到,则调用相应的回调函数。
事件驱动主要执行过程是当进来的一个新的请求的时候,请求将会被压入队列中,然后通过一个循环来检测队列中的事件状态变化,如果检测到有状态变化的事件,那么就执行该事件对应的处理代码(一般都是回调函数)。
基于事件驱动的,先同步(即按从上到下的顺序)执行整个整个js文件中的代码(此时的事件循环是暂停的),当遇到异步函数时,会从线程池中寻求有用的线程来执行该异步函数,当异步函数执行完,就将回调函数放入消息队列里面。当整个js文件执行完后,事件循环开始执行,从消息队列里面取消息,开始执行里面的回调函数。
异步I/O
最后再来说异步I/O,NodeJs采用了事件循环的方式实现异步I/O。以下是整个异步I/O的流程:
NodeJs优缺点
所以说因为异步I/O,大家说Node擅长处理I/O密集型的应用场景;因为单线程,在CPU密集的场景中,Node因为大量CPU的计算会阻塞JavaScript线程导致大家说Node不擅长处理CPU密集型场景。但是这里有两点要注意,第一,并不是说Node处理大量CPU计算就慢,而且因为单线程会阻塞其他操作,单以执行效率来做评价,V8的执行效率是毋庸置疑的。第二,Node也有单线程大计算的解决方案:采用和Web Workers相同的思路,子进程来应对单线程无法利用多核CPU的问题。
引用和参考
深入浅出NodeJs