NodeJS异步机制和基本原理
单线程
NodeJS是单线程,单线程有以下好处:
- 简单
- 高性能,避免了频繁的线程切换开销
- 占用资源小,因为是单线程,在大负荷情况下,对内存占用仍然很低
- 线程安全,没有加锁、解锁、死锁这些问题
如何解决高并发?
node使用异步IO和事件驱动(回调函数)来解决高并发这个问题。
一般来说,高并发解决方案会提供多线程模型,为每个业务逻辑提供一个线程,通过系统线程切换来来弥补同步I/O调用的时间开销。像apache,是一个请求一个线程。
而NodeJS使用的是单线程模型,对所有I/O都采用异步的请求方式,避免频繁的上下文切换,在NodeJS执行的时候维护着一个事件队列;程序在执行时进入事件循环等待下一个事件到来,每个异步I/O请求完成后都会被推送到事件队列中的等待执行。
NodeJS的异步机制是基于事件的,所有的I/O、网络通信、数据库查询都以非阻塞的方式执行,返回结果由事件循环来处理。NodeJS在同一时刻只会处理一个事件,完成后立即进入事件循环检查后面事件。这样CPU和内存在同一时间集中处理一件事,同时尽量让耗时的I/O等操作并行执行。
事件循环机制
所谓事件循环是指NodeJS会把所有的异步操作使用事件机制解决,有个线程在不断地循环检测事件队列。
NodeJS中所有的逻辑都是事件的回调函数,所以NodeJS始终在事件循环中,程序入口就是事件循环第一个事件的回调函数。事件的回调函数中可能会发出I/O请求或直接发射( emit)事件,执行完毕后返回事件循环。事件循环会检查事件队列中有没有未处理的事件,直到程序结束。NodeJS的事件循环对开发者不可见,由libev库实现,libev不断检查是否有活动的、可供检测的事件监听器,直到检查不到时才退出事件循环,程序结束。
libuv 是一个高性能事件驱动的程序库,封装了 Windows 和 Unix 平台一些底层特性,为开发者提供了统一的 API. 因此,NodeJS 是单线程,异步非阻塞。
但毕竟,如何弥补单线程缺陷?是不是有异步非阻塞,就可以高枕无忧了?
不是的。
CPU密集型任务存在短板
如上所述,NodeJS的机制是单线程,这个线程里面,有一个事件循环机制,处理所有的请求。如图所示。在事件处理过程中,它会智能地将一些涉及到IO、网络通信等耗时比较长的操作,交由worker threads去执行,执行完了再回调,这就是所谓的异步IO非阻塞吧。但是,那些非IO操作,只用CPU计算的操作,它就自己扛了,比如算什么斐波那契数列之类。它是单线程,这些自己扛的任务要一个接着一个地完成,前面那个没完成,后面的只能干等。因此,对CPU要求比较高的CPU密集型任务多的话,就有可能会造成号称高性能,适合高并发的NodeJS服务器反应缓慢。
无法利用CPU的多核
最开始,线程只是用于分配单个处理器处理时间的一种机制。但假如操作系统本身支持多个CPU/内核,那么每个线程都可以得到一个不同自己的CPU/内核,实现真正的“并行运算”。在这种情况下,多线程程序可以提高资源使用效率。NodeJS是单线程程序,它只有一个event loop,也只占用一个CPU/内核。现在大部分服务器都是多CPU或多核的,当NodeJS程序的event loop被CPU密集型的任务占用,导致有其它任务被阻塞时,却还有CPU/内核处于闲置的状态,造成资源的浪费。
解决方案
利用原生模块或第三方模块,开辟进程或子进程,用于处理这些特殊的任务。
如果有异常抛出,因为是单线程,整个项目将不可用。
但这归根到底是代码的问题,糟糕的代码,不管什么体系,都会有问题,即使不崩溃。解决办法是用pm2等工具来运行?
NodeJS与JavaScript的关系
NodeJS本身不是开发语言,它是一个工具或者平台,在服务器端解释、运行javascript;coffeescript属于NodeJS体系,算是一种新的开发语言,但它的目的在于最后编译成javascript。
NodeJS利用Google V8来解释运行javascript,但是系统真正执行的代码是用C++写的。javascript做的只是调用这些API而已。因此,并无执行效率的问题。
NodeJS适用场景
RESTful API
这是适合 Node 的理想情况,因为您可以构建它来处理数万条连接。它仍然不需要大量逻辑;它本质上只是从某个数据库中查找一些值并将它们组成一个响应。由于响应是少量文本,入站请求也是少量的文本,因此流量不高,一台机器甚至也可以处理最繁忙的公司的 API 需求。
实时程序
比如聊天服务
聊天应用程序是最能体现 NodeJS 优点的例子:轻量级、高流量并且能良好的应对跨平台设备上运行密集型数据(虽然计算能力低)。同时,聊天也是一个非常值得学习的用例,因为它很简单,并且涵盖了目前为止一个典型的 NodeJS 会用到的大部分解决方案。
单页APP
ajax很多。现在单页的机制似乎很流行,比如phonegap做出来的APP,一个页面包打天下的例子比比皆是。
总而言之,NodeJS适合运用在高并发、I/O密集、少量业务逻辑的场景。