node.js在项目中应该放在哪个位置

用了node.js这么长时间,对node.js擅长和不擅长的领域算是比较清晰了。

进程与线程

进程是计算机中已运行程序的实体,一个进程可以包含多个线程,多个线程共同某个进程的工作。一个CPU同一时间只能处理某个进程的任务。所有的线程共享着计算机的内存,没有做任何的隔离。但是,为了保证某些数据的安全,会在内存中使用互斥锁(Mutual exclusion,缩写 Mutex)信号量(Semaphore)。互斥锁允许且只允许同一时间只有一个线程操作共享内存,其它线程必须等待该线程处理完成后再对该内存块进行处理;信号量的逻辑与互斥锁相似,只是同一时间允许N个线程对共享内存进行操作,当名额满了之后其他线程必须等待。
这篇文章很好的解释了进程与线程的关系,以及他们对CPU和内存的使用方式。

阻塞I/O和非阻塞I/O

写程序,操作文件、读写数据库和请求第三方服务等都是常有的事,这些都是I/O,I/O是非常耗时间的。

当程序采用阻塞I/O的策略时,线程遇到I/O操作就会等待,直到I/O操作结束,再继续执行,例如PHP语言,就是采用这种机制。那么PHP采用这种机制,如果一个请求由于I/O操作导致线程被阻塞,是否会影响其它请求的响应时间呢,答案是不会的,看多线程与单线程里面的解释。

当程序采用非阻塞I/O的策略时,线程遇到I/O操作时,会通知另外的线程去处理,然后主线程挂起一个回调函数,并继续执行其他的任务,不会做任何的等待,直到这个I/O操作完成,另外的线程将结果返回给主线程,主线程调用之前挂起的回到函数,继续执行接下来的操作。

node.js就是采用非阻塞I/O和事件轮询的方式。我们知道Javascript单进程单线程的语言,但是所谓的单线程只是说他执行任务时用的是一个线程,我们称之为主线程,既然有主线程,那就说明肯定还有其他线程,是的,就是任务队列,专门负责处理I/O操作,当node.js的主线程发现了一个异步行为,他会将该任务挂起,将他提交给任务队列去处理,直到任务队列处理完该任务并返回处理结果时,主线程再调用处理该结果的回调函数继续执行。通过这样的方式,主线程不需要等待任何I/O操作,使主线程的资源利用率成倍提升。

单线程与多线程

上面的内容中提到,PHP采用了阻塞I/O的方案,该方案会等待I/O操作结束再继续执行接下来的代码。那么这样的方式,如果同时多个请求进来了,由于I/O阻塞的原因会不会出现某个请求执行了很久,导致后面的请求响应慢的问题,答案是不会的。因为PHP采用了多线程的处理方案,当有一个请求进来的时候,PHP就会开启一个线程来处理一个请求,一个请求对应一个线程,那么一个请求所出现的问题是不会影响到另一个请求的(CPU和内存富足的情况下)。PHP的这种方案使得各线程之间相对安全,不会互相影响,但是弊端也是明显的,当I/O出现时,PHP始终处于等待状态,这导致CPU的利用率低,并且,一个请求进来就创建一个线程,这对内存的要求较高,因此,在高并发的情况下,需要横向扩展PHP服务器以满足高并发的需求,很多时候都是因为线程过多导致内存不足的问题。

node.js的非阻塞I/O和事件轮询机制很好的优化了这个问题,通过非阻塞I/O提高了CPU的利用率,并且单个线程对内存的需求肯定比PHP少得多,因此node.js更能扛得住高并发。但任何事情都是双面的,有优点就必然有确定,单线程的javascript,如果某个请求出现了异常,就会导致整个进程不用了,当然,我们有解决方案可以让程序在出现异常的情况下自动重启。还有就是如果你在node.js的主线程执行了高CPU运算的操作,那将是灾难。因为在主线程中,除了I/O是异步的,其他运算都是同步的,一个高CPU运算的操作会导致后续的请求全部被卡住。

因此,node.js虽然被很多人追捧,但是,如果用的不好,还不如写PHP。node.js更适合做任务的分发者而不是执行者!!!

架构图

如果我有一个团队,我更愿意这样去搭建一个后端的服务,node.js不太适合出现在数据层,除非真的只是增删查改而没有其他高耗CPU的操作,node.js更适合作为前端的路由去分发请求,他自身不应该出现过多的CPU操作,如果有,请用fork。

文章目录
  1. 1. 进程与线程
  2. 2. 阻塞I/O和非阻塞I/O
  3. 3. 单线程与多线程
,