iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > node.js >Node.js中的进程、线程、协程与并发模型是什么
  • 945
分享到

Node.js中的进程、线程、协程与并发模型是什么

2024-04-02 19:04:59 945人浏览 泡泡鱼
摘要

这篇文章主要介绍“node.js中的进程、线程、协程与并发模型是什么”,在日常操作中,相信很多人在node.js中的进程、线程、协程与并发模型是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方

这篇文章主要介绍“node.js中的进程、线程、协程与并发模型是什么”,在日常操作中,相信很多人在node.js中的进程、线程、协程与并发模型是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Node.js中的进程、线程、协程与并发模型是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

Node.js中的进程、线程、协程与并发模型是什么

进程

我们一般将某个程序正在运行的实例称之为进程,它是操作系统进行资源分配和调度的一个基本单元,一般包含以下几个部分:

  • 程序:即要执行的代码,用于描述进程要完成的功能;

  • 数据区域:进程处理的数据空间,包括数据、动态分配的内存、处理函数的用户栈、可修改的程序等信息;

  • 进程表项:为了实现进程模型,操作系统维护着一张称为进程表的表格,每个进程占用一个进程表项(也叫进程控制块),该表项包含了程序计数器、堆栈指针、内存分配情况、所打开文件的状态、调度信息等重要的进程状态信息,从而保证进程挂起后,操作系统能够正确地重新唤起该进程。

进程具有以下特征:

  • 动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的;

  • 并发性:任何进程都可以同其他进程一起并发执行;

  • 独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;

  • 异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进。

需要注意的是,如果一个程序运行了两遍,即便操作系统能够使它们共享代码(即只有一份代码副本在内存中),也不能改变正在运行的程序的两个实例是两个不同的进程的事实。

在进程的执行过程中,由于中断、CPU 调度等各种原因,进程会在下面几个状态中切换:

Node.js中的进程、线程、协程与并发模型是什么

  • 运行态:此刻进程正在运行,并占用了 CPU;

  • 就绪态:此刻进程已准备就绪,随时可以运行,但因为其它进程正在运行而被暂时停止;

  • 阻塞态:此刻进程处于阻塞状态,除非某个外部事件(比如键盘输入的数据已到达)发生,否则进程将不能运行。

通过上面的进程状态切换图可知,进程可以从运行态切换成就绪态和阻塞态,但只有就绪态才能直接切换成运行态,这是因为:

  • 从运行态切换成就绪态是由进程调度程序引起的,因为系统认为当前进程已经占用了过多的 CPU 时间,决定让其它进程使用 CPU 时间;并且进程调度程序是操作系统的一部分,进程甚至感觉不到调度程序的存在;

  • 从运行态切换成阻塞态是由进程自身原因(比如等待用户的键盘输入)导致进程无法继续执行,只能挂起等待某个事件(比如键盘输入的数据已到达)发生;当相关事件发生时,进程先转换为就绪态,如果此时没有其它进程运行,则立刻转换为运行态,否则进程将维持就绪态,等待进程调度程序的调度。

线程

有些时候,我们需要使用线程来解决以下问题:

  • 随着进程数量的增加,进程之间切换的成本将越来越大,CPU 的有效使用率也会越来越低,严重情况下可能造成系统假死等现象;

  • 每个进程都有自己独立的内存空间,且各个进程之间的内存空间是相互隔离的,而某些任务之间可能需要共享一些数据,多个进程之间的数据同步就过于繁琐。

关于线程,我们需要知道以下几点:

  • 线程是程序执行中的一个单一顺序控制流,是操作系统能够进行运算调度的最小单位,它包含在进程之中,是进程中的实际运行单位;

  • 一个进程中可以包含多个线程,每个线程并行执行不同的任务;

  • 一个进程中的所有线程共享进程的内存空间(包括代码、数据、堆等)以及一些资源信息(比如打开的文件和系统信号);

  • 一个进程中的线程在其它进程中不可见。

了解了线程的基本特征,下面我们来聊一下常见的几种线程类型。

内核态线程

内核态线程是直接由操作系统支持的线程,其主要特点如下:

  • 线程的创建、调度、同步、销毁由系统内核完成,但其开销较为昂贵;

  • 内核可将内核态线程映射到各个处理器上,能够轻松做到一个处理器核心对应一个内核线程,从而充分地竞争与利用 CPU 资源;

  • 仅能访问内核的代码和数据;

  • 资源同步与数据共享效率低于进程的资源同步与数据共享效率。

用户态线程

用户态线程是完全建立在用户空间的线程,其主要特点如下:

  • 线程的创建、调度、同步、销毁由用户空间完成,其开销非常低;

  • 由于用户态线程由用户空间维护,内核根本感知不到用户态线程的存在,因此内核仅对其所属的进程做调度及资源分配,而进程中线程的调度及资源分配由程序自行处理,这很可能造成一个用户态线程被阻塞在系统调用中,则整个进程都将会阻塞的风险;

  • 能够访问所属进程的所有共享地址空间和系统资源;

  • 资源同步与数据共享效率较高。

轻量级进程(LWP)

轻量级进程(LWP)是建立在内核之上并由内核支持的用户线程,其主要特点如下:

  • 用户空间只能通过轻量级进程(LWP)来使用内核线程,可看作是用户态线程与内核线程的桥接器,因此只有先支持内核线程,才能有轻量级进程(LWP);

  • 大多数轻量级进程(LWP)的操作,都需要用户态空间发起系统调用,此系统调用的代价相对较高(需要在用户态与内核态之间进行切换);

  • 每个轻量级进程(LWP)都需要与一个特定的内核线程关联,因此:

    • 与内核线程一样,可在全系统范围内充分地竞争与利用 CPU 资源;

    • 每个轻量级进程(LWP)都是一个独立的线程调度单元,这样即使有一个轻量级进程(LWP)在系统调用中被阻塞,也不影响整个进程的执行;

    • 轻量级进程(LWP)需要消耗内核资源(主要指内核线程的栈空间),这样导致系统中不可能支持大量的轻量级进程(LWP);

  • 能够访问所属进程的所有共享地址空间和系统资源。

小结

上文我们对常见的线程类型(内核态线程、用户态线程、轻量级进程)进行了简单介绍,它们各自有各自的适用范围,在实际的使用中可根据自己的需要自由地对其进行组合使用,比如常见的一对一、多对一、多对多等模型,由于篇幅限制,本文对此不做过多介绍,感兴趣的同学可自行研究。

协程

协程(Coroutine),也叫纤程(Fiber),是一种建立在线程之上,由开发者自行管理执行调度、状态维护等行为的一种程序运行机制,其特点主要有:

  • 因执行调度无需上下文切换,故具有良好的执行效率;

  • 因运行在同一线程,故不存在线程通信中的同步问题;

  • 方便切换控制流,简化编程模型。

javascript 中,我们经常用到的 async/await 便是协程的一种实现,比如下面的例子:

function updateUserName(id, name) {
  const user = getUserById(id);
  user.updateName(name);
  return true;
}

async function updateUserNameAsync(id, name) {
  const user = await getUserById(id);
  await user.updateName(name);
  return true;
}

上例中,函数 updateUserNameupdateUserNameAsync 内的逻辑执行顺序是:

  • 调用函数 getUserById 并将其返回值赋给变量 user

  • 调用 userupdateName 方法;

  • 返回 true 给调用者。

两者的主要区别在于其实际运行过程中的状态控制:

  • 在函数 updateUserName 的执行过程中,按照前文所述的逻辑顺序依次执行;

  • 在函数 updateUserNameAsync 的执行过程中,同样按照前文所述的逻辑顺序依次执行,只不过在遇到 await 时,updateUserNameAsync 将会被挂起并保存挂起位置当前的程序状态,直到 await 后面的程序片段返回后,才会再次唤醒 updateUserNameAsync 并恢复挂起前的程序状态,然后继续执行下一段程序。

通过上面的分析我们可以大胆猜测:协程要解决的并非是进程、线程要解决的程序并发问题,而是要解决处理异步任务时所遇到的问题(比如文件操作、网络请求等);在 async/await 之前,我们只能通过回调函数来处理异步任务,这很容易使我们陷入回调地狱,生产出一坨坨屎一般难以维护的代码,通过协程,我们便可以实现异步代码同步化的目的。

需要牢记的是:协程的核心能力是能够将某段程序挂起并维护程序挂起位置的状态,并在未来某个时刻在挂起的位置恢复,并继续执行挂起位置后的下一段程序。

I/O 模型

一个完整的 I/O 操作需要经历以下阶段:

  • 用户进(线)程通过系统调用向内核发起 I/O 操作请求;

  • 内核对 I/O 操作请求进行处理(分为准备阶段和实际执行阶段),并将处理结果返回给用户进(线)程。

我们可将 I/O 操作大致分为阻塞 I/O非阻塞 I/O同步 I/O异步 I/O 四种类型,在讨论这些类型之前,我们先熟悉下以下两组概念(此处假设服务 A 调用了服务 B):

  • 阻塞/非阻塞

    • 如果 A 只有在接收到 B 的响应之后才返回,那么该调用为阻塞调用

    • 如果 A 调用 B 后立即返回(即无需等待 B 执行完毕),那么该调用为非阻塞调用

  • 同步/异步

    • 如果 B 只有在执行完之后再通知 A,那么服务 B 是同步的;

    • 如果 A 调用 B 后,B 立刻给 A 一个请求已接收的通知,然后在执行完之后通过回调的方式将执行结果通知给 A,那么服务 B 就是异步的。

很多人经常将阻塞/非阻塞同步/异步搞混淆,故需要特别注意:

  • 阻塞/非阻塞针对于服务的调用者而言;

  • 同步/异步针对于服务的被调用者而言。

了解了阻塞/非阻塞同步/异步,我们来看具体的 I/O 模型

阻塞 I/O

定义:用户进(线)程发起 I/O 系统调用后,用户进(线)程会被立即阻塞,直到整个 I/O 操作处理完毕并将结果返回给用户进(线)程后,用户进(线)程才能解除阻塞状态,继续执行后续操作。

特点:

  • 由于该模型会阻塞用户进(线)程,因此该模型不占用 CPU 资源;

  • 在执行 I/O 操作的时候,用户进(线)程不能进行其它操作;

  • 该模型仅适用于并发量小的应用,这是因为一个 I/O 请求就能阻塞进(线)程,所以为了能够及时响应 I/O 请求,需要为每个请求分配一个进(线)程,这样会造成巨大的资源占用,并且对于长连接请求来说,由于进(线)程资源长期得不到释放,如果后续有新的请求,将会产生严重的性能瓶颈。

非阻塞 I/O

定义:

  • 用户进(线)程发起 I/O 系统调用后,如果该 I/O 操作未准备就绪,该 I/O 调用将会返回一个错误,用户进(线)程也无需等待,而是通过轮询的方式来检测该 I/O 操作是否就绪;

  • 操作就绪后,实际的 I/O 操作会阻塞用户进(线)程直到执行结果返回给用户进(线)程。

特点:

  • 由于该模型需要用户进(线)程不断地询问 I/O 操作就绪状态(一般使用 while 循环),因此该模型需占用 CPU,消耗 CPU 资源;

  • I/O 操作就绪前,用户进(线)程不会阻塞,等到 I/O 操作就绪后,后续实际的 I/O 操作将阻塞用户进(线)程;

  • 该模型仅适用于并发量小,且不需要及时响应的应用。

同(异)步 I/O

用户进(线)程发起 I/O 系统调用后,如果该 I/O 调用会导致用户进(线)程阻塞,那么该 I/O 调用便为同步 I/O,否则为 异步 I/O

判断 I/O 操作同步异步的标准是用户进(线)程与 I/O 操作的通信机制,其中:

  • 同步情况下用户进(线)程与 I/O 的交互是通过内核缓冲区进行同步的,即内核会将 I/O 操作的执行结果同步到缓冲区,然后再将缓冲区的数据复制到用户进(线)程,这个过程会阻塞用户进(线)程,直到 I/O 操作完成;

  • 异步情况下用户进(线)程与 I/O 的交互是直接通过内核进行同步的,即内核会直接将 I/O 操作的执行结果复制到用户进(线)程,这个过程不会阻塞用户进(线)程。

Node.js 的并发模型

Node.js 采用的是单线程、基于事件驱动的异步 I/O 模型,个人认为之所以选择该模型的原因在于:

  • JavaScript 在 V8 下以单线程模式运行,为其实现多线程极其困难;

  • 绝大多数网络应用都是 I/O 密集型的,在保证高并发的情况下,如何合理、高效地管理多线程资源相对于单线程资源的管理更加复杂。

总之,本着简单、高效的目的,Node.js 采用了单线程、基于事件驱动的异步 I/O 模型,并通过主线程的 EventLoop 和辅助的 Worker 线程来实现其模型:

  • Node.js 进程启动后,Node.js 主线程会创建一个 EventLoop,EventLoop 的主要作用是注册事件的回调函数并在未来的某个事件循环中执行;

  • Worker 线程用来执行具体的事件任务(在主线程之外的其它线程中以同步方式执行),然后将执行结果返回到主线程的 EventLoop 中,以便 EventLoop 执行相关事件的回调函数。

需要注意的是,Node.js 并不适合执行 CPU 密集型(即需要大量计算)任务;这是因为 EventLoop 与 JavaScript 代码(非异步事件任务代码)运行在同一线程(即主线程),它们中任何一个如果运行时间过长,都可能导致主线程阻塞,如果应用程序中包含大量需要长时间执行的任务,将会降低服务器的吞吐量,甚至可能导致服务器无法响应。

到此,关于“Node.js中的进程、线程、协程与并发模型是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: Node.js中的进程、线程、协程与并发模型是什么

本文链接: https://www.lsjlt.com/news/98342.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Node.js中的进程、线程、协程与并发模型是什么
    这篇文章主要介绍“Node.js中的进程、线程、协程与并发模型是什么”,在日常操作中,相信很多人在Node.js中的进程、线程、协程与并发模型是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方...
    99+
    2024-04-02
  • Golang协程与并发模型
    go 中的协程是一种轻量级并发机制,允许在同一个进程中执行多个任务。它们共享进程内存空间,可以通过通道进行通信。此外,文章还提供了以下内容:协程创建使用 go 关键字。通道通过 make...
    99+
    2024-04-15
    协程 并发模型 golang
  • Node.js中的单线程模型是什么
    这期内容当中小编将会给大家带来有关Node.js中的单线程模型是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。1、高并发一般来说,高并发的解决方案就是多线程模型,服务...
    99+
    2024-04-02
  • Node.js中进程与线程的作用是什么
    本篇内容主要讲解“Node.js中进程与线程的作用是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Node.js中进程与线程的作用是什么”吧!1. 回顾进程...
    99+
    2024-04-02
  • 什么是进程、线程、协程
    什么是进程? 我们都知道计算机的核心是CPU,它承担了所有的计算任务;而操作系统是计算机的管理者,它负责任务的调度、资源的分配和管理,统领整个计算机硬件;应用程序则是具有某种功能的程序,程序是运行于操...
    99+
    2023-09-06
    java jvm linux
  • Node.js中的进程和线程是什么
    这篇文章主要介绍“Node.js中的进程和线程是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Node.js中的进程和线程是什么”文章能帮助大家解决问题。一、进...
    99+
    2024-04-02
  • 七、并发编程(进程与线程)
    一、前言 进程即正在执行的一个过程。进程是对正在运行程序的一个抽象。 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一。操作系统的其他所有内容都是围绕进程的概念展开的。    PS:即使可...
    99+
    2023-01-30
    线程 进程
  • python中强制关闭线程、协程与进程的方法是什么
    这篇“python中强制关闭线程、协程与进程的方法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“python中强制关闭...
    99+
    2023-07-05
  • golang中协程与线程的区别是什么
    golang中协程与线程的区别有”调度器“、”内存和性能“、”锁和同步“和”异常处理“四点:1、协程则是由 Go 语言运行时调度的,而线程是由操作系统内核调度的;2、协程在相同的堆栈空间内运行,而线程都需要独立的堆栈空间和上下文切换的开销;...
    99+
    2023-12-12
    Golang golang线程 Golang协程
  • Java多线程并发与并行和线程与进程案例
    目录一、并发与并行二、线程与进程三、创建线程类前言: 程序在没有跳转语句的前提下,都是由上至下依次执行,那现在想要设计一个程序,边打游戏边听歌,怎么设计? 要解决上述问题,咱们得使用...
    99+
    2024-04-02
  • Python中多线程、多进程、协程的区别是什么
    今天就跟大家聊聊有关Python中多线程、多进程、协程的区别是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。首先我们写一个简化的爬虫,对各个功能细分,有意识进行函数式编程。下面代...
    99+
    2023-06-16
  • 掌握 Python 并发编程:揭秘协程、线程和进程
    并发编程是编写同时执行多个任务的代码的艺术,在 Python 中提供了协程、线程和进程等多种选项。了解这些选项及其适用场景对于开发高效、可扩展的应用程序至关重要。 协程 协程是 Python 中一种轻量级的并发机制,允许一个函数暂停执行...
    99+
    2024-02-18
    协程 线程 进程 并发 Python
  • Java 线程池与并发编程的协同作用
    引言 在当今高并发应用盛行的时代,线程池和并发编程已成为提高应用程序性能和可扩展性的关键技术。,为开发人员提供了强大的工具集,可以有效管理并发任务并优化应用程序性能。 Java 线程池 Java 线程池是一个预先创建的线程集合,可按需分...
    99+
    2024-03-13
    线程池
  • JUC并发编程中进程与线程的示例分析
    这篇文章将为大家详细讲解有关JUC并发编程中进程与线程的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。进程与线程进程程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至 CPU,...
    99+
    2023-06-29
  • Java并发编程中的内存模型是什么
    这篇文章主要介绍“Java并发编程中的内存模型是什么”,在日常操作中,相信很多人在Java并发编程中的内存模型是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java并发编程中的内存模型是什么”的疑惑有所...
    99+
    2023-06-25
  • 详解JUC并发编程中的进程与线程学习
    目录进程与线程进程线程同步异步串行并行执行时间创建和运行线程Thread 与 Runnable 的关系原理分析查看进程线程运行原理线程上下文切换start与run方法sleep方法s...
    99+
    2024-04-02
  • Java多线程并发、并行、线程与进程实例分析
    本篇内容介绍了“Java多线程并发、并行、线程与进程实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、并发与并行并发:指两个或多个事...
    99+
    2023-07-02
  • go语言中协程与线程的区别是什么
    区别:1、一个线程可以多个协程,一个进程也可以单独拥有多个协程;2、线程是同步机制,而协程则是异步;3、协程能保留上一次调用时的状态,线程不行;4、线程是抢占式,协程是非抢占式的;5、线程是被分割的CPU资源,协程是组织好的代码流程,协程需...
    99+
    2023-05-14
    Golang go语言 协程 线程
  • Java并发编程之volatile与JMM多线程内存模型
    目录一、通过程序看现象二、为什么会产生这种现象(JMM模型)?三、MESI 缓存一致性协议 一、通过程序看现象 在开始为大家讲解Java 多线程缓存模型之前,我们先看下面的这一段代码...
    99+
    2024-04-02
  • Android中的单线程模型是什么
    这篇文章给大家介绍Android中的单线程模型是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Android 单线程模型详解及实例当第一次启动一个Android程序时,Android会自动创建一个称为“main”主...
    99+
    2023-05-31
    android 单线 roi
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作