Node.js 中的线程 与 并发

Node.js
Node.js 中的线程 与并发

jcLee95 :https://blog.csdn.net/qq_28550263?spm=1001.2101.3001.5343
邮箱 :291148484@163.com

本文地址:https://blog.csdn.net/qq_28550263/article/details/129784985


目 录

  • 1. JavaScript 与线程
    • 1.1 JavaScript 是单线程语言
    • 1.2 浏览器中的线程
    • 1.3 electron 中的线程
      • 主进程
      • 渲染器进程
    • 1.4 创建额外线程
  • 2. 事件循环 与异步消息执行机制
    • 事件 与 消息的产生
    • 队列中消息的处理
    • 添加消息
    • 执行栈 与 同步任务的执行
    • 异步任务的执行
    • 概括
  • 3. Node.js 并发
    • 3.1 概述
    • 3.2 exec
      • 异步进程创建 API
      • 同步进程创建 API
    • 3.3 execFile
      • 异步进程创建 API
      • 同步进程创建 API
    • 3.4 spawn
      • 异步进程创建 API
      • 同步进程创建 API
    • 3.5 fork


1. JavaScript 与线程

1.1 JavaScript 是单线程语言

是的——作为单线程语言 JavaScript 拓展包括 文件IO 在内的各种 API 的运行时 NodeJS,仍然是以单线程的模式运行的。

线程 是指同时运行多个任务或程序的执行。每个能够执行代码的单元称为线程。

1.2 浏览器中的线程

一般除非使用 web worker ,不然 JavaScript 只在线程中运行。浏览器中的线程包括 主线程 和 页面线程。

  • 主线程用于浏览器处理用户事件和页面绘制等。
  • 一般而言,浏览器在一个线程中运行一个页面中的所有 JavaScript 脚本,以及呈现布局,回流,和垃圾回收。

下面这张图来源于 https://www.google.com/googlebooks/chrome/,形象地描述了 Chromium 中的进程关系:
https://www.google.com/googlebooks/chrome/

1.3 electron 中的线程

electron 是一个十分特殊的运行环境,它既拥有 NodeJS 运行时的API,也拥有浏览器的渲染界面。 Electron 框架在架构上非常相似于一个现代的网页浏览器,其的线程继承与 Chromium 中的线程,包括 主线程 和 渲染线程。

主进程

主进程的主要目的是 创建 和 管理 应用程序窗口,就行浏览器管理其页面那样。每个 Electron 应用都有一个单一的主进程,作为应用程序的入口点。 主进程在 Node.js 环境中运行,这意味着它具有 require 模块和使用所有 Node.js API 的能力。

渲染器进程

渲染器进程 简称 渲染进程。 每个 Electron 应用都会为每个打开的窗口生成一个单独的渲染器进程,这和浏览器中的页面进程(线程)是类似的。 洽如其名,渲染器负责 渲染 网页内容。 所以实际上,运行于渲染器进程中的代码是须遵照网页标准的 。

因此,一个浏览器窗口中的所有的用户界面和应用功能,都应与您在网页开发上使用相同的工具和规范来进行攥写。

1.4 创建额外线程

在早期,浏览器通常使用单个进程来处理所有这些功能。 虽然这种模式意味着您打开每个标签页的开销较少,但也同时意味着一个网站的崩溃或无响应会影响到整个浏览器。随着 JavaScript 技术发展至今,我们已经可以创建独立执行,同时能相互通信的额外进程。这得益于 Web Workers 相关技术。通过使用 Web Workers,Web 应用程序可以在独立于主线程的后台线程中,运行一个脚本操作。这样做的好处是可以在独立线程中执行费时的处理任务,从而允许主线程(通常是 UI 线程)不会因此被阻塞/放慢。

2. 事件循环 与异步消息执行机制

JavaScript 中,事件循环机制 负责执行代码、收集和处理事件以及执行队列中的子任务。之所以称之为 事件循环,是因为它经常按照类似如下的方式来被实现:

while (queue.waitForMessage()) {
  queue.processNextMessage();
}

一个 JavaScript 运行时包含了一个待处理消息的消息队列。每一个消息都关联着一个用以处理这个消息的 回调函数

事件 与 消息的产生

每当一个事件发生 并且有一个 事件监听 器绑定在该事件上时,对应的一个消息就会被添加进 消息队列。如果没有事件监听器,这个事件将会丢失。

队列中消息的处理

而对 于在消息处理队列,在 事件循环 期间的某个时刻,运行时会从最先进入队列的 消息 开始处理队列中的消息。被处理的消息会被移出队列,并作为输入参数来调用与之关联的函数。调用一个函数总是会为其创造一个新的栈帧

例如,当一个带有点击事件处理器的元素被点击时,产生了一个点击的消息加入到消息队列,直到后续处理到该消息时, 运行时会将该消息移出消息队列,然后执行这个消息的某些定义的回调函数,即所谓 关联的函数。这些关联函数可以通过相关API指定,比如对于点击事件:

const elem = document.getElementById("myBt");
elem.addEventListener("click", (event)=>{
  // 关联函数(该点击事件的回调函数)
})

添加消息

出了如 web 中的事件能够发出消息外,我们也可以手动地往消息队列中添加消息。例如我们可以使用一个 setTimeout 函数往消息队列中 添加异步消息。

// 注:
// 浏览器中,window.setTimeout 和 setTimeout 是一回事。setTimeout中的this指向 Window 对象
// nodeJS中,setTimeout中的this 指向 Timeout 对象
window.setTimeout(()=>{
  console.log("Hello, setTimeout!")
}, 2000);

该函数接受两个参数:

  • 待加入队列的消息
    这个时间值代表了消息被实际加入到队列的最小延迟时间。
    如果队列中没有其他消息并且栈为空,在这段延迟时间过去之后,消息会被马上处理。
    但是,如果有其他消息,setTimeout 消息必须等待其他消息处理完。
  • 一个时间值。
    需要指出的是,从以上讨论我们可知。这个参数仅仅表示最少延迟时间,而非确切的等待时间。

由于 setTimeout 添加的消息是异步的。异步消息只有在运行时执行完消息处理队列中的同步消息后才会被处理,处理时相应执行其关联函数。

执行栈 与 同步任务的执行

执行栈 是一个表示同步任务执行顺序的栈,主线程只执行来自执行栈的同步任务,被执行完成的任务将会出栈,直到 执行栈被清空。此过程中不会理会任何异步任务。

异步任务的执行

即使有相应的消息表明某些事件的发生,异步任务在执行栈未清空时都将被挂起。然而一旦执行栈清空,添加到消息队列中的消息按照之前所介绍的逻辑逐个出队,并执行对应的事件处理程序。直到消息队列中所有的消息均被处理完成。

概括

  • JavaScript 运行时通过 单线程循环 处理事件;
  • 所谓 事件,其实就是表示 消息被处理
  • 所谓 (事件的)回调函数,其实就是消息关联的函数;也就是 当消息被处理时 所执行的该 消息所绑定的函数,也称 事件处理程序
  • 所谓 任务,无非是 处理消息执行消息绑定的函数
  • 任务有两种类型,即所谓 同步任务异步任务
  • 运行时 先依次对 执行栈 中的所有 同步任务 出栈并执行,直到将其清空;
  • 执行栈清空后,消息队列 中的异步消息逐个出队,交由 运行时处理以完成他们的事件处理程序,直到 消息队列清空。

3. Node.js 并发

3.1 概述

既然 NodeJS 是单线程的,那么怎么还可以实现并发呢?其实 NodeJS 可以通过创建多个子进程来实现,这一切都需要用到一个特殊的模块:child_process

child_process 模块来创建子进程的主要方法有如下:

方法描述
exec生成一个shell,然后在该 shell 中执行命令,缓冲子进程的生成的输出。传递给exec函数的命令字符串由shell直接处理。
execFile与 exec 类似,只是它在默认情况下不生成shell
spawn使用给定的命令行参数生成一个新的进程,命令行参数在args中。如果省略,args默认为空数组。
fork方法是 spawn() 的特例,专门用于生成新的Node.js进程。返回一个ChildProcess对象。返回的ChildProcess将有一个额外的内置通信通道,允许消息在父进程和子进程之间来回传递。

3.2 exec

该函数的语法格式如下:

异步进程创建 API

child_process.exec(command[, options][, callback])

参数:

  • command 要运行的命令,参数以空格分隔。
  • options 选项参数:
    • cwd <string> | <URL> 子进程的当前工作目录。
    • env 环境键值对。默认为 process.env
    • encoding 默认为'utf8'
    • shell 用来执行命令的Shell,Unix 上默认为 '/bin/sh',windows上默认为 process.env.ComSpec
    • signal 允许使用AbortSignal中止子进程。
    • timeout 默认为 0。
    • maxBuffer stdout或stderr上允许的最大数据量(以字节为单位)。如果超过,子进程将被终止,任何输出都将被截断。默认为 1024 * 1024
    • killSignal <string> | <integer> 默认为 'SIGTERM'
    • uid <number> 设置进程的用户标识
    • gid <number> 设置进程的组标识
    • windowsHide <boolean> 隐藏通常在Windows系统上创建的子进程控制台窗口。
  • callback 当进程终止时用输出调用的回调函数。
    • error <Error>
    • stdout <string> | <Buffer>
    • stderr <string> | <Buffer>

返回:

  • <ChildProcess>

同步进程创建 API

child_process.execSync(command[, options])

参数:

  • command 要运行的命令。
  • options 可选参数,参考异步API。

返回:

  • <Buffer> | <string> 命令的标准输出。

3.3 execFile

child_process.execFile() 函数类似于child_process.exec(),只是它在默认情况下不生成shell。相反,指定的可执行文件作为一个新进程直接生成,比child_process.exec()更有效。

异步进程创建 API

child_process.execFile(file[, args][, options][, callback])

同步进程创建 API

child_process.execFileSync(file[, args][, options])

3.4 spawn

该函数的语法格式如下:

异步进程创建 API

child_process.spawn(command[, args][, options])

同步进程创建 API

child_process.execSync(command[, options])

3.5 fork

该函数的语法格式如下

child_process.fork(modulePath[, args][, options])

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/4663.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

8种特“坑”的 SQL 写法,性能降低100倍

给大家分享几个SQL常见的“坏毛病”及优化技巧。 SQL语句的执行顺序&#xff1a; 1、LIMIT 语句 分页查询是最常用的场景之一&#xff0c;但也通常也是最容易出问题的地方。比如对于下面简单的语句&#xff0c;一般 DBA 想到的办法是在 type、 name、 create_time 字段上加组…

春分-面试

青岛 zc&#xff1a; 1.String的类型 string、stringbuilder 、stringbuffer&#xff1f; String不可变、另外两个可变、StringBuilder线程不安全、但是效率高、并且String不能被继承。 JVM是C写的编译后的机器码&#xff0c; 2.集合类的用法&#xff0c;还问了键值对。key如果…

06solr 文件删除

文章目录 0x01 漏洞介绍0x02 影响版本0x03 漏洞环境0x04 漏洞复现0x05 修复建议摘抄免责声明0x01 漏洞介绍 Apache Solr 存在任意文件删除漏洞,在目前的最新版本(8.8.2)中仍然未被修复,漏洞的根本成因是函数 **Files.deleteIfExists()**对要删除的文件名并未做校验。同时 Apa…

小程序面试题(day07)

文章目录前言微信小程序自定义tabbar的理解&#xff1f;微信小程序怎么缓存数据&#xff1f;微信小程序怎么进行网络请求&#xff1f;微信小程序路由跳转以及传参如何实现&#xff1f;微信小程序生命周期的理解&#xff1f;微信小程序模块化&#xff1f;微信小程序所有api放在哪…

高并发系统设计:缓存、降级、限流、(熔断)

高并发系统设计&#xff1a;缓存、降级、限流、(熔断) 在开发高并发系统时有三把利器用来保护系统&#xff1a;缓存、降级和限流。 非核心服务可以采用降级、熔断&#xff0c;核心服务采用缓存和限流&#xff08;隔离流量可以最大限度的保障业务无损&#xff09;。 缓存 缓…

Scala隐式转换

Scala 的隐式转换是一种自动类型转换机制&#xff0c;它可以在编译器自动插入一些代码&#xff0c;将一个类型自动转换成另一个类型。这种转换可以发生在函数调用、赋值、类型转换等多种场景中。 隐式转换的机制可以让 Scala 代码更加简洁、优雅。例如&#xff0c;我们可以通过…

“体育游戏第一股”投资未来,望尘科技走向价值兑现周期

2022年的游戏市场&#xff0c;遗憾以疲弱之势落下帷幕。游戏市场规模与用户数量&#xff0c;均出现了小幅下降&#xff0c;显示出存量市场的典型特征。 但与此同时&#xff0c;更多垂直领域的拳头产品、响应市场需求的精品游戏&#xff0c;却屡屡掀起热潮。去年随世界杯而来的…

Darknet-YOLOv4训练步骤

1、打开终端&#xff0c;克隆项目 git clone https://github.com/AlexeyAB/darknet.git2、修改Makefile文件 其中&#xff0c;GPU和CUDNN是GPU加速&#xff0c;CUDNN_HALF是特定硬件加速&#xff0c;OPENCV是否使用OpenCV&#xff0c;AVX和OPENMP是CPU加速opencv编译问题htt…

JavaScript常用知识点

1-包装数据类型 一个基本数据类型当你使用的时候会自动转换成复杂数据类型&#xff0c;当你使用完毕&#xff0c;会自动转换为基本数据类型 比如 字符串 string是基本数据类型&#xff0c;但是它可以使用 length这个方法 &#xff0c;就是因为字符串也是一个包装数据类型&…

Spring整合

Spring整合6&#xff0c;Spring整合6.1 Spring整合Mybatis思路分析6.1.1 环境准备步骤1:准备数据库表步骤2:创建项目导入jar包步骤3:根据表创建模型类步骤4:创建Dao接口步骤5:创建Service接口和实现类步骤6:添加jdbc.properties文件步骤7:添加Mybatis核心配置文件步骤8:编写应用…

Canny 边缘检测算法-python实现(附代码)

文章目录1、调用opencv进行canny边缘检测2、图像灰度化3、高斯模糊处理4、图像梯度、梯度幅值、梯度方向计算5、NMS&#xff08;非极大值抑制&#xff09;6、双阈值的边界选取摘要 : Canny 边缘检测算法由计算机科学家 John F. Canny 于 1986 年提出的。其不仅提供了算法&#…

【Python】更精美的俄罗斯方块开发指南(步骤已写)

文章目录前言一、游戏介绍二、源码剖析1.引入库2.读入数据总结前言 最近想找一些Python相关的游戏开发例子&#xff0c;正好在itch.io上闲逛看到这个俄罗斯方块项目&#xff0c;瞬间被惊艳到了。作者是 Mikhail &#xff0c;项目(tetris_for_two)地址是&#xff1a; https://g…

数据库原理及应用(四)——SQL语句(2)SQL基础查询以及常见运算符

一、SELECT语句基础 数据库查询是数据库的核心操作&#xff0c;SELECT 语句用于从数据库中选取数据。 SELECT [ALL/DISTINCT] <列名>,<列名>...FROM <表名或视图名>,<表名或视图名>[WHERE <条件表达式>][GROUP BY <列名1> [HAVING <条…

Jetpack compose:炫酷的按钮点击效果

Jetpack compose&#xff1a;炫酷的按钮点击效果 屏幕的每个组件在与用户交互时都有其给用户反馈的方式。例如&#xff0c;当用户触摸 Toggle 按钮时&#xff0c;它会更改其状态以响应交互。这种交互给用户一种感觉。 在此博客中&#xff0c;我们将实现一些自定义点击效果&…

Air700E开发板|移芯EC618|4G Cat.1模组:概述及PinOut

文章目录基础资料概述主要功能外设分布PinOut&#xff08;管脚定义&#xff09;管脚功能说明固件升级正常开机模式&#xff1a;下载模式&#xff1a;IO 电平选择基础资料 Air700E文档中心 概述 EVB-Air700E 开发板是合宙通信推出的基于 Air700E 模组所开发的&#xff0c;包含…

AI遮天传 NLP-词表示

本文重点在第三部分“词嵌入”及对Word2vec的介绍&#xff0c;前面的知识主要用于小白对词表示和一些定义、名称的理解&#xff0c;和对一些方法不足的思考。一、词表示1.1 词表示的定义词表示是一种将自然语言中的词转换为机器可理解含义的过程其中意思&#xff08;meaning&am…

Docker之安装Docker

安装Docker1. Docker 基本组成2. 安装Docker3. 阿里云镜像加速4. 底层原理1. Docker 基本组成 镜像&#xff08;image&#xff09; docker 镜像就好比是一个模板&#xff0c;可以同通过这个模板来创建容器服务&#xff0c;如&#xff1a;tomcat 镜像 > run > tomcat1 容器…

网络技术这十个术语你知道吗?

你好&#xff0c;这里是网络技术联盟站。 网络技术术语是指在计算机网络领域中所使用的专业术语。由于计算机技术的快速发展&#xff0c;网络技术术语也在不断地更新和发展。本文将对网络技术术语进行一些介绍和解释&#xff0c;以帮助读者更好地了解和掌握网络技术。 一、协…

内网Nexus代理yum、epel 源私有仓库 + 内网设备配置(centos)

一、准备 一些常用的镜像开源站 yum: 阿里开源镜像源&#xff1a;http://mirrors.aliyun.com/centos 网易开源镜像站&#xff1a;http://mirrors.163.com/ Centos社区镜像站&#xff1a;http://mirror.centos.org/centos/ 中科大开源镜像站&#xff1a;http://centos.ustc.edu…

Web3中文|World ID与GPT-4同时上线,OpenAI创始人的另一场探险?

这两天GPT-4的到来&#xff0c;再次成为朋友圈及媒体热议的话题。此次升级、更新让大家看到了AI给科技和社会带来的潜在挑战性甚至革命性。在赞叹AI迅速发展的同时&#xff0c;也让人再次聚焦关注其背后拥有超强开发和创新能力的OpenAI团队。 令人刮目相看的是&#xff0c;由A…