您好,欢迎访问一九零五行业门户网

nodejs是单进程的吗

nodejs是单进程。node遵循的是单线程单进程的模式,但其基于事件驱动、异步非阻塞模式,可以应用于高并发场景,避免了线程创建、线程之间上下文切换所产生的资源开销。
本教程操作环境:windows7系统、nodejs 12.19.0版、dell g3电脑。
进程 
进程 process 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础,进程是线程的容器 (来自百科) 。进程是资源分配的最小单位。我们启动一个服务、运行一个实例,就是开一个服务进程,例如 java 里的 jvm 本身就是一个进程,node.js 里通过 node app.js 开启一个服务进程,多进程就是进程的复制 (fork) ,fork 出来的每个进程都拥有自己的独立空间地址、数据栈,一个进程无法访问另外一个进程里定义的变量、数据结构,只有建立了 ipc 通信,进程之间才可数据共享。
线程
线程是操作系统能够进行运算调度的最小单位,首先我们要清楚线程是隶属于进程的,被包含于进程之中。 一个线程只能隶属于一个进程,但是一个进程是可以拥有多个线程的。 单线程 单线程就是一个进程只开一个线程 javascript 就是属于单线程,程序顺序执行(这里暂且不提js异步),可以想象一下队列,前面一个执行完之后,后面才可以执行,当你在使用单线程语言编码时切勿有过多耗时的同步操作,否则线程会造成阻塞,导致后续响应无法处理。你如果采用 javascript 进行编码时候,请尽可能的利用 javascript 异步操作的特性。
nodejs单进程单线程事件驱动node遵循的是单线程单进程的模式,node的单线程是指js的引擎只有一个实例,且在nodejs的主线程中执行,同时node以事件驱动的方式处理io等异步操作。node的单线程模式,只维持一个主线程,大大减少了线程间切换的开销,但是会有多个worker线程,用于执行异步操作。
但是node的单线程使得在主线程不能进行cpu密集型操作,否则会阻塞主线程。对于cpu密集型操作,在node中通过 child_process 可以创建独立的子进程,父子进程通过ipc通信,子进程可以是外部应用也可以是node子程序,子进程执行后可以将结果返回给父进程。
node.js的运行机制v8引擎解析javascript脚本。解析后的代码,调用node api。libuv库负责node api的执行。它将不同的任务分配给不同的worker线程,形成一个event loop(事件循环),以异步的方式将任务的执行结果返回给v8引擎。v8引擎再将结果返回给用户。
这个图是整个 node.js 的运行原理,从左到右,从上到下,node.js 被分为了四层,分别是 应用层、v8引擎层、node api层 和 libuv层。
应用层: 即 javascript 交互层,常见的就是 node.js 的模块,比如 http,fsv8引擎层: 即利用 v8 引擎来解析javascript 语法,进而和下层 api 交互nodeapi层: 为上层模块提供系统调用,一般是由 c 语言来实现,和操作系统进行交互 。libuv层: 是跨平台的底层封装,实现了 事件循环、文件操作等,是 node.js 实现异步的核心node.js 事件循环node.js 通常情况下是单进程的。
主线程运行 v8 和 javascript多个子线程通过 事件循环 被调度事件循环:
事件循环是一种编程构造,用于等待和分派程序中的事件或消息, 主线程从任务队列中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为event loop(事件循环)
事件队列:
当用户的网络请求或者其它的异步操作到来时,node都会把它放到event queue之中,此时并不会立即执行它,代码也不会被阻塞,继续往下走,直到主线程代码执行完毕。
任务队列:
任务队列是一个事件的队列(也可以理解成消息的队列),io设备完成一项任务,就在任务队列中添加一个事件,表示相关的异步任务可以进入执行栈了。主线程读取任务队列,就是读取里面有哪些事件。
事件驱动:
实质是通过主循环加事件触发方式运行程序
node
node.js 不是一门语言也不是框架,它只是基于 google v8 引擎的 javascript 运行时环境,是对 js 功能的拓展。提供了网络、文件、dns 解析、进程线程等功能。
libuv
libuv是专门为node.js开发的一个封装库,提供跨平台的异步i/o能力。
注意:
一个事件循环有一个或多个任务队列。一个任务队列是一组的任务
libuv 主要是,利用系统提供的事件驱动模块解决网络异步 io,利用线程池解决文件io。另外还实现了定时器,对进程、线程等使用进行了封装。
其实这里的事件循环和js在浏览器的事件循环是一样的,主线程允许同步代码,异步代码放到对应的工作线程中执行,回调执行结果后放进事件队列,待主线程执行事件队列的任务。
事件驱动+事件循环实现高并发具体执行顺序:
1、每个node.js进程只有一个主线程在执行程序代码,形成一个执行栈(execution context stack)
2、主线程之外,还维护了一个事件队列(event queue)。当用户的网络请求或者其它的异步操作到来时,node都会把它放到event queue之中,此时并不会立即执行它,代码也不会被阻塞,继续往下走,直到主线程代码执行完毕。
3、主线程代码执行完毕完成后,然后通过event loop,也就是事件循环机制,开始到event queue的开头取出第一个事件,从线程池中分配一个线程去执行这个事件,接下来继续取出第二个事件,再从线程池中分配一个线程去执行,然后第三个,第四个。主线程不断的检查事件队列中是否有未执行的事件,直到事件队列中所有事件都执行完了,此后每当有新的事件加入到事件队列中,都会通知主线程按顺序取出交eventloop处理。当有事件执行完毕后,会通知主线程,主线程执行回调,线程归还给线程池。
注意
我们所看到的node.js单线程只是一个js主线程与ui渲染共享一个线程,本质上的异步操作还是由线程池完成的,node将所有的阻塞操作都交给了内部的线程池去实现,本身只负责不断的往返调度,并没有进行真正的i/o操作,从而实现异步非阻塞i/o,这便是node单线程和事件驱动的精髓之处了。
总结:1、libuv 线程池默认打开 4 个,最多打开 128个 线程。(例如:以前 web 服务器同一时间比如说最多只能接收 100 个请求,多的就无法接收了,服务器就挂掉了。nodejs 所谓的高并发是指可以同时接收 1000、10000 个请求,只不过以排队的方式在等待。)
2、主线程执行js,是单线程的,js代码在做大量计算就是cpu密集了。主线程不空闲出来也没法处理 io 的事,所以就会阻塞了。
3、回调只能保证某个请求按照顺序执行,不能保证多个请求访问一个资源的先后顺序,多个请求访问一个资源是要加锁的,用事务加锁就行。
【推荐学习:《nodejs 教程》】
以上就是nodejs是单进程的吗的详细内容。
其它类似信息

推荐信息