探秘NodeJs·NodeJs的进程

探秘NodeJs·NodeJs的进程之谜

什么是进程

进程是操作系统分配资源的最小单位。进程是应用程序的执行副本

进程总体来说都是存在于内存当中的,当然,当我们的设备内存不足的时候,操作系统可能会使用虚拟内存技术,将非进行中的进程交换到硬盘当中,用以满足设备内存不足时进行中进程运行需求。

启动应用程序流程

应用程序(磁盘) -> 进程(内存)

启动应用程序时操作系统会做些什么

在启动应用程序的过程中,操作系统将会给进程分配以下资源:

  • 用户和组:是哪个用户、组启动的进程

  • 目录资源

    • 进程的工作目录

      进程工作目录即执行应用程序的的目录,也就是开启进程的目录。如下图,我们开启了一个nodejs的进程,那么,使用process.cwd()就可以看到进程的工作目录。

    • 进程的可见目录

  • 文件资源

    • 设备资源
    • 网络资源
    • 数据资源
    • 代码资源
    • ...
  • 主线程

    • 注意:进程是不能执行程序的。执行程序的是线程。操作系统会给每一个进程分配一个主线程,然后进程还可以分配其他线程

NodeJs的进程

Node.js的进程也是进程,进程下有很多的线程。进程是Node引擎执行的副本,是操作系统分配资源的最小单位。在NodeJs中由很多线程一起完成执行程序的任务。

  • NodeJs进程也有主线程
  • NodeJs进程也可以使用多线程(只不过不允许用户使用。因此网络上说NodeJs是单线程实际上描述是不准确的,准确的说法是:"NodeJs本身是多线程的,但是只对用户开放单线程")
  • NodeJs进程有工作目录
  • NodeJs进程可以拥有文件资源
  • ...

总而言之,操作系统给进程的资源,NodeJs进程也都能享受到,操作系统不给进程的,NodeJs进程也没有。从这个层面上看,其实NodeJs进程和JavaPython进程没什么区别。

NodeJs的线程模型

进程是分配资源(系统资源)的,线程是执行程序的

为什么不设计一个"既可以分配资源,又可以执行程序的模型呢?这样进程和线程的概念不就统一了吗?"

其实,在操作系统设计的早期,确实是这么设计的。但是随着时代和技术的发展,一个应用能干的事情越来越多,而创建和销毁进程是比较耗费时间和资源的,因此,才会在进程下面设计了线程的概念,允许一个进程同时开启多个线程完成多项任务,而线程只需要执行程序相关的资源即可,创建和销毁的耗时和资源都比进程小很多。

线程之间本身是共享内存的,因此,创建一个新线程不需要像创建进程一样需要去申请内存空间,而是彼此共享同一个进程所申请的内存空间。

以下为线程执行程序相关的资源:

  • 程序计数器:用来标记程序执行到哪一行了
  • :用于存储执行程序的中间结果
  • (虚拟)寄存器:用于辅助计算以及控制

形象的说:进程如果是秒级的,那么线程就是毫秒级的

那么,问一个问题:NodeJs是单进程吗?

其实,并没有单进程的说法,只有单线程,进程作为应用程序执行的副本,本身就是一个完整的整体,所以也没有多进程的说法。

再问一个问题:NodeJs是单线程吗?

NodeJs不是单线程的,在NodeJs内部有很多个线程。但用户执行的NodeJs程序只会运行在一个线程当中。

我们平时经常使用的定时器,如:setTimeout,之所以能够不阻塞主线程的其他代码,异步执行,就是因为NodeJs引擎为setTimeout单独开启了一个新的线程用于处理其中的任务。

总结一下:线程的本质是抽象需要并行(concurrent)执行的任务,比如说:

  • 浏览器的渲染
  • 用户操作界面
  • 发送网络请求

以上三个任务,其实我们完全可以让他们并行的执行,这样,在用户操作界面时,同时也可以进行浏览器渲染和发送网络请求的任务。

NodeJs中,每做一件需要操作系统支持的事情,就会使用一个单独的线程。比如说:

  • 读取文件
  • 发送网络请求
  • 定时器
  • ...

为了防止线程过多,在NodeJs中有一个线程池用于处理需要操作系统支持的行为。

因此,其实我们可以把上面所说所有跟操作系统有关的事情,都开成一个"外部服务",而其他与操作系统无关的事情都是在一个线程中执行的。那么我们就可以把用户执行的程序看做是"单线程 "的。因为所有单线程无法完成的任务,都由NodeJs引擎开启的其他线程处理了。

NodeJs为什么不给用户提供多线程能力

NodeJsIO密集型的应用,我们经常在做的事情都是在读取写入文件或请求发送接口。我们不会用NodeJs去做一些计算密集型的任务,如:图像识别、神经网络计算等。即使目前市面上存在的一些用于神经网络计算的js框架,也仅仅是作为连接桥连接底层CC++之类其他语言写的核心服务。因此,NodeJs其实并不需要给用户提供多线程的能力。

NodeJs的事件循环模型

我们都知道,在浏览器中也存在事件循环的概念,那么,浏览器中的事件循环跟NodeJs中的事件循环有什么区别吗?

我们先来看一下NodeJs中事件循环的示意图:

以下为浏览器事件循环的示意图:

我们可看到,两者本质上并没有什么区别。

那么,**事件循环(Event Loop)**到底是什么呢?

  • 它是一个单线程的程序(用户程序+Event Loop是一个单线程程序,而涉及操作系统的功能则会开一个新的线程处理)
  • 它是驱动 javascript 程序执行的动力源

Event Loop 赋予了原本单线程的用户程序并发的能力,它将单线程的执行拆分了很多任务

我们通常将用户程序称为:主栈程序(Main Stack),本质上,事件循环和用户程序在同一个线程中执行,因此也是发生在主栈上。

而定时器、网络请求、数据库操作、文件操作等都是发生在线程池上的。

宏任务与微任务

浏览器会先执行主栈任务,当主栈没有有要执行的任务时,会进入消息循环,有任务先执行宏任务,任何一个宏任务执行完都检查有没有微任务。

总体来说,宏任务是由宿主发起的,而微任务使用JavaScript发起的

相关推荐
腾讯TNTWeb前端团队38 分钟前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰4 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪4 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪4 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy5 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom6 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom6 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom6 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom6 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom6 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试