探秘NodeJs·NodeJs的进程

探秘NodeJs·NodeJs的进程之谜

什么是进程

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

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

启动应用程序流程

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

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

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

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

  • 目录资源

    • 进程的工作目录

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

      探秘NodeJs·NodeJs的进程

    • 进程的可见目录

  • 文件资源

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

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

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的进程

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

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

探秘NodeJs·NodeJs的进程

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

探秘NodeJs·NodeJs的进程

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

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

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

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

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

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

宏任务与微任务

探秘NodeJs·NodeJs的进程

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

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

原文链接:https://juejin.cn/post/7327570230774546466 作者:kinertang

(0)
上一篇 2024年1月25日 上午11:09
下一篇 2024年1月25日 下午4:00

相关推荐

发表回复

登录后才能评论