很少分享技术文章,写的不好的地方请大家多多指教,本文是自己对于node.js的一些见解,如有纰漏请在评论区交流。
高并发策略
通常高并发的解决方案就是提供多线程模型,服务器为每个客户端请求分配一个线程,使用同步 I/O,系统通过线程切换来弥补同步I/O调用的时间开销。
但是当并发请求越多创建的线程也越多,这样创建、销毁线程以及在线程间切换所需的开销也是非常大的。
Node.js采用了单线程模型来处理,不会为每个请求分配一个线程,而是用一个主线程处理所有的请求,然后对I/O操作进行异步处理,避开了创建、销毁线程以及在线程间切换所需的开销和复杂性。所以这就是为什么node.js适合IO密集型任务而不适合计算密集型任务
node.js 异步IO
异步IO是指操作系统提供的IO(数据进出)的能力,比如:磁盘的读写,DNS的查询,数据库的连接,网络请求的处理,等等;线程发出IO操作指令,然后就可以去做别的事情了(线程不需要等待),所有操作完成后再执行回调。
libuv 的IO线程池
nodejs中的异步I/O是通过底层的libuv提供的多线程的线程池来完成的。所以Node.js 的单线程仅仅是指 JavaScript 运行在单线程中,而并非 Node.js 是单线程。
IO线程执行IO操作时,会调用一个系统函数,生成一个请求包向内核传递,内核知道将这个I/O操作发送给哪个硬件设备。异步IO同时会传入一个回调函数随着请求包传递给设备驱动程序,然后IO线程返回线程池执行下一个IO事件。当异步I/O请求完成时,设备驱动程序就会生成一个I/O完成包,会由IO线程提取完成I/O的请求包,并将之前的回调函数推入node.js的task Queue中,等待事件循环将它推入主线程的执行栈执行。
node.js 事件循环(event loop)
每当我们运行一个node.js程序时,就会自动创建一个主线程。这个线程是执行js代码的唯一地方。在主线程内部,会生成了一个叫事件循环的东西。这个循环的作用是调度我们主线程在哪个时间点应该执行的操作。
运行程序后不会立即生成事件循环。它会在整个程序执行完后运行
Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。事件就是主题,注册到这个事件的回调函数就是观察者
通过上图简单讲一下node.js的事件循环,当程序执行到异步事件时,比如计时器(setTimeout等),promise, io请求等,会将事件推入事件队列。
如果是IO操作,事件循环会将事件推给异步IO线程池,完成返回回调函数到task Queue, 非IO操作(setTimout等)会调用操作系统API执行,然后返回到callback quque. 然后根据事件循环的不同阶段从queue中取出callback函数推入主线程的执行栈中执行。
至于事件循环的阶段不是本文的重点,可以参考官网event loop指南这里就不细讲了。
如果有疑问请在评论区留言交流!