一位入门者关于 JavaScript 单线程的一些思考

news2024/9/22 7:36:18

在这里插入图片描述

人们一提起 JavaScript 就会想起单线程,那么为什么会这样呢?这经得住推敲吗?不同的执行环境又有什么差异呢?

带着这些问题,我通过自问自答的方式,整理了一份关于 Javascript 单线程的知识汇总

整体的思考过程如下图,每个问题在后面有单独的回答

Created with Raphaël 2.3.0 大家常说 JavaScript 单线程,那么: 1. JavaScript 的单线程模型是什么含义? 2.造成 JavaScript 单线程模型的 原因是什么呢?是语言本身的原因吗? 单线程其行为和 不同 js 引擎的有关吗? 4. Nodejs 的底层 (libuv) 的实现方式, 是单线程的吗? 6. nodejs 都有哪些多线程能力? 他们的使用场景是什么? 3.浏览器的 event loop 实现方式, 是单线程的吗? 5. 如何使用 Web Workers?

1. JavaScript 的单线程模型,具体是什么含义?

JavaScript的单线程模型指的是在给定的执行环境(如一个浏览器标签页或一个Node.js进程)中,JavaScript 代码的执行是在单个线程上顺序进行的。这意味着一次只能执行一个任务,其他任务必须等待当前执行中的任务完成后才能执行

其具体含义包括:

  1. 同步执行: 代码按照书写的顺序从上到下执行,一个函数的执行必须等待上一个函数执行完毕。
  2. 无竞态条件: 由于同时只有一个任务在执行,因此 不会出现多线程编程中常见的竞态条件问题
  3. 事件队列: 单线程模型采用事件队列机制来处理异步事件。当异步事件发生时(如点击事件、网络请求返回等),它们会被放入事件队列中,等待当前执行栈中的所有代码执行完毕后,事件循环再按顺序从事件队列中取出事件进行处理。
  4. 非阻塞I/O: 为了避免长时间的I/O操作阻塞线程,JavaScript环境通常提供了非阻塞的I/O操作(如网络请求、文件读取等),允许代码在发起I/O操作后立即继续执行,而I/O结果会在未来某个时刻通过回调函数、Promise等形式处理。
  5. Web Workers: 虽然JavaScript自身是单线程的,但现代浏览器提供了Web Workers允许开发者创建真正的后台线程来执行复杂计算,不过这些线程无法直接访问DOM。

单线程模型简化了开发者对程序执行流程的理解和状态管理,但也意味着开发者需要注意编写非阻塞代码,以避免长时间的计算或同步I/O操作导

2. 这是否主要是因为,JavaScript 语言本身没有提供良好的跨线程能力,例如锁机制等?

JavaScript 语言最初设计为运行在浏览器环境中,用于增强用户与网页之间的交互。因此,它的设计哲学是尽量简单,避免复杂性,以便于开发人员编写和维护。在早期的Web开发中,页面通常不需要执行复杂的计算任务,因此单线程模型足够满足需求。

单线程模型的确是因为JavaScript语言在设计之初没有包括多线程编程的能力。这样的设计可以避免多线程编程中的一些困难:

  • 锁机制: 在多线程环境中,为了同步资源访问,通常需要复杂的锁机制。JavaScript省略了这些复杂性,因为一次只执行一个任务,资源不会同时被多个任务访问。
  • 竞态条件: 多线程编程易于出现竞态条件,这需要开发者仔细设计程序以防止错误。JavaScript的单线程模型避免了这些问题。
  • 上下文切换: 多线程编程中,线程间的上下文切换可能会导致性能下降。JavaScript的单线程模型没有这个问题。

3. 浏览器的 event loop 实现方式,是单线程的吗?

是的,浏览器中的事件循环(event loop)是基于单线程的。尽管现代浏览器是多进程的,每个标签页通常都有自己的进程,但事件循环是在每个标签页的渲染进程中独立执行的,并且是单线程的。这意味着在给定的标签页中,JavaScript 代码是在单个线程上按顺序执行的,这个线程通常被称为“主线程” 或 “UI线程”。

主线程负责执行代码、渲染界面、处理事件等任务。尽管如此,浏览器还提供了 Web Workers,允许开发者在后台线程上运行代码,但这些线程不能直接访问 DOM,并且与主线程的通信是通过消息传递的方式进行的,以保持界面的响应性。

4. Nodejs 的底层 (libuv) 的 event loop 实现方式,是单线程的吗?

是的,libuv 的事件循环(event loop)默认情况下是单线程的。libuv 是一个高性能的异步I/O库,常用于支持 Node.js 的非阻塞I/O操作。它提供了一个跨平台的事件循环,用于处理文件系统操作、网络操作等。

在 libuv 中,事件循环运行在一个单一的线程上,通常是应用程序的主线程。所有的异步事件(如文件I/O完成通知、网络消息到达等)都会被推送到事件队列中,然后由事件循环依次处理。

虽然 libuv 的事件循环是单线程的,但它 也使用了线程池来执行一些阻塞的操作,比如文件系统I/O,以避免阻塞主线程。当这些操作完成时,它们的结果会被推回事件循环,由主线程处理完成事件。

因此,虽然 libuv 本身处理事件的方式是单线程的,但它通过工作线程来支持并发执行耗时任务,这样就可以在不阻塞主线程的情况下处理这些任务。

libuv 官网标注的使用线程池的任务类型包括

  • File system operations:文件系统操作
  • DNS functions (getaddrinfo and getnameinfo):DNS 相关函数(getaddrinfogetnameinfo
  • User specified code via uv_queue_work():用户通过 uv_queue_work() 指定代码。

此外,nodejs 线程池的大小是可以配置的。默认是 4 个线程。

5. 如何使用 Web Workers?

Web Workers 允许你在后台线程中运行代码,从而不阻塞主线程。这对于执行耗时的计算任务特别有用,因为它们不会冻结用户界面或影响前端的响应性。

场景
假设你需要在一个网页应用中执行复杂的数据处理或计算密集型任务,比如图像处理、大量数据排序、执行复杂算法等。

示例代码
下面是一个简单的使用Web Workers的示例,其中我们将创建一个worker来执行耗时的任务(比如计算斐波那契数列)。

主线程代码(main.js):

// 检查是否支持Web Workers
if (window.Worker) {
    // 创建一个新的Worker对象,并指定要运行的脚本
    const myWorker = new Worker('worker.js');

    // 发送数据到worker
    myWorker.postMessage(10); // 假设我们要计算斐波那契数列的第10个数字

    // 监听来自worker的消息
    myWorker.onmessage = function(e) {
        console.log('Message received from worker:', e.data);
    };

    // 监听错误
    myWorker.onerror = function(e) {
        console.error('Error occurred in worker:', e);
    };
} else {
    console.log('Your browser doesn\'t support web workers.');
}

Worker线程代码(worker.js):

// 监听主线程发来的消息
onmessage = function(e) {
    console.log('Message received from main script:', e.data);
    const result = fibonacci(e.data);
    postMessage(result);
};

// 斐波那契数列递归函数
function fibonacci(n) {
    return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
}

// 监听错误事件
onerror = function(e) {
    console.error('Error occurred in worker:', e);
};

在上面的例子中,主线程通过 postMessage 方法向 worker 发送一个消息,worker 接收这个消息,并开始执行计算斐波那契数列的函数。计算完成后,worker 通过 postMessage 方法将结果发送回主线程。主线程通过 onmessage事件监听器来接收这个结果。

注意事项

  • Worker 线程无法直接访问 DOM 元素。(原因前面已经介绍过了,这样避免了资源竞争,即想通 DOM 元素的并发修改)
  • Workers 之间以及 Workers 与主线程之间只能通过消息传递(拷贝或转移数据)进行通信,不能共享状态。
  • Workers 中不能访问一些全局变量和函数,比如 windowdocument 等。(道理类似)

6. nodejs 都有哪些多线程能力?他们的使用场景是什么?

Node.js 提供了多种方式来实现多线程和并行处理,每种方式都适用于不同的场景:

  • Worker Threads:
    • 能力: 提供真正的多线程支持,每个线程都有自己的V8实例。
    • 场景: CPU密集型任务,如加密、数据分析、图像处理等。
    • 注意点: 需要小心处理线程间的通信和状态共享,以避免竞态条件。
  • Cluster 模块:
    • 能力: 创建多个进程,进程间不共享内存,但可以共享服务器端口。
    • 场景: 提高网络服务的吞吐量,如Web服务器、API服务等。
    • 注意点: 主要用于分摊负载和提高容错性,并不提供共享状态的能力。
  • child_process 模块:
    • 能力: 创建子进程来执行命令或独立的Node.js脚本。
    • 场景: 需要与系统命令交互或运行与主进程独立的任务。
    • 注意点: 子进程的资源使用和管理需要仔细控制,以避免过多消耗系统资源。

使用场景举例

  • 使用 Worker Threads 进行图像处理:图像处理通常需要大量的CPU资源进行像素计算。你可以在Worker线程中进行图像处理,以免阻塞主线程。
  • 使用 Cluster 模块扩展 Web 服务器:当运行一个Node.js网站时,你可以使用Cluster模块来创建多个子进程,这些子进程可以并行处理更多的用户请求。(感觉上这很类似于 nginx 的多进程)
  • 使用 child_process 运行脚本或命令:
    当你需要执行系统级别的任务,如脚本运行、文件压缩等,可以通过创建子进程来并行执行,而不会影响主进程。

优点

Node.js 的多线程和并发处理能力提供了在单线程事件循环模型之外的扩展性。这些机制可以帮助你优化应用的性能,特别是在处理CPU密集型或需要并行处理的任务时。

谨慎使用

并不是所有的场景都需要使用多线程。在大多数情况下,Nodejs 的非阻塞I/O和事件驱动模型已经提供了足够的性能。多线程应该作为一种优化手段,在必要时才使用。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI学习记录 - gpt如何进行token化,理论知识,以GPT2为举例

AI学习记录已经发了十几篇&#xff0c;大佬们可以看看&#xff0c;如果有帮助动动小手点赞 token入门版&#xff0c;有空会更新具体代码操作&#xff0c;能学到一点东西的话&#xff0c;大佬们点个赞&#xff01;&#xff01;&#xff01; GPT4当中&#xff0c;我们提问问题是…

Webpack构建工具

1 概述 Webpack 是一个现代 JavaScript 应用程序的静态模块打包器&#xff08;module bundler&#xff09;。 它的主要作用是将多个松散的模块&#xff0c;包括 JavaScript、CSS、图片、字体等资源&#xff0c;按照指定的规则和依赖关系打包成一个或多个优化后的静态资源文件…

基于RHEL7系统搭建PXE技术体系

目录 一、kickstart自动化安装脚本制作 1、实验前提 2、安装图形界面并启动&#xff0c;关闭DHCP服务 3、安装图形化生成kickstart自动安装脚本的工具并启动 二、搭建DHCP服务并测试脚本 1、安装dhcp 2、生成配置文件 3、编辑配置文件 三、搭建pxe网络安装环境实现服务…

centos安装maven

1.下载maven 去官网选择自己需要的版本 Maven – Download Apache Maven 复制链接 2.使用wget下载 先切换到opt文件夹 再将复制的链接使用wget下载 因为wget下载速度很慢&#xff0c;所以这里使用https://mirrors.tuna.tsinghua.edu.cn镜像 cd /opt wget https://mirrors.tu…

交易困境如何克服,可以先浏览Anzo Capital 昂首资本官网

是不是经常有这样的交易员&#xff0c;常因感到“我知道得不够多”而在交易中做出不合逻辑的行为。在这种心态下&#xff0c;交易员总想寻找更优秀的交易者、更佳的买卖时机以及更有效的策略。事实上&#xff0c;这类追求往往陷入过多无用信息的泥潭&#xff0c;让人难以甄别哪…

【系统架构设计师】二十五、大数据架构设计理论与实践③

目录 六、大数据架构设计案例分析 6.1 Lambda架构在某网奥运中的大数据应用 6.2 Lambda架构在某网广告平台的应用与演进 6.2.1 第一版架构 6.2.1 第二版架构 6.2.3 第三版架构 6.3 某证券公司大数据系统 6.4 某电商智能决策大数据系统 六、大数据架构设计案例分析 6.…

centos上传工具

yum install lrzsz 安装完成之后 作用是 输入 rz 可以本地上传文件

【生成式人工智能-八-大型语言模型的能力评估】

语言模型的能力评估 评估难度来自哪里输出没办法确定给出选择题本身就没标准答案 评估方法人力用语言模型来评估语言模型语言模型的偏爱 评估语言模型的数据集评估模型的不同能力阅读长文的能力心智测验道德性测试安全性测试 通常情况下我们想到的语言模型能力评估&#xff0c;…

图神经网络实战(18)——消息传播神经网络

图神经网络实战&#xff08;18&#xff09;——消息传播神经网络 0. 前言1. 消息传播神经网络2. 实现 MPNN 框架小结系列链接 0. 前言 我们已经学习了多种图神经网络 (Graph Neural Networks, GNN) 变体&#xff0c;包括图卷积网络 (Graph Convolutional Network, GCN)、图注意…

在macOS平台上通过Jenkins远程打包报错,提示errSecInternalComponent

问题&#xff1a;在macOS平台上通过Jenkins远程打包报错&#xff0c;提示errSecInternalComponent 原因 出现这个问题的主要原因&#xff1a;Jenkins以ssh方式到slave机上&#xff0c;默认是没有账户的&#xff0c;但是访问钥匙串要求必须有用户身份 通过Xcode打包的过程中&am…

Ps:通过 RGB 值计算 HSB 值

在 Photoshop 中&#xff0c;HSB&#xff08;色相、饱和度和明度&#xff09;仅作为表达颜色的一种方式而存在&#xff0c;并不是一种颜色模式。 色相/饱和度命令就是基于色彩三要素进行调色的常用命令。 还有一个与 HSB 相关的滤镜&#xff1a;HSB/HSL 滤镜&#xff0c;用于实…

无人机培训机构推广运营理论技术

一、市场定位与品牌建设 在无人机培训行业的激烈竞争中&#xff0c;精准的市场定位是成功的第一步。首先&#xff0c;需明确目标学员群体&#xff0c;如航拍爱好者、农业植保服务者、应急救援人员或专业无人机操作员等。基于目标群体的需求&#xff0c;构建差异化的品牌形象。…

一个升级的多租户权限管理系统,组件化,模块化,轻耦合,高扩展企业级的应用框架,功能强大(附源码)

前言 在现代软件开发中&#xff0c;多租户权限管理系统是企业级应用中的一个关键组件。然而&#xff0c;现有的一些框架&#xff0c;如RuoYi&#xff0c;虽然提供了一些基本的功能&#xff0c;但在面对更复杂的企业级需求时&#xff0c;如原生的MyBatis使用、复杂的分页处理&a…

【桥接模式】设计模式系列:分离抽象与实现的艺术(构建可扩展性的桥梁)

文章目录 Java设计模式系列之桥接模式&#xff1a;分离抽象与实现1. 引言2. 设计模式简介桥接模式定义桥接模式与其他模式的区别 3. 桥接模式的基本原理模式的核心概念抽象化与实现化的分离实现细节的封装解耦的机制 4. 桥接模式的角色介绍角色介绍UML和时序图代码示例说明 5. …

.Net Core IIS 程序报错 Access to the path c:\\windows\\TEMP\\poifiles is denied

程序运行报错&#xff1a;Access to the path c:\\windows\\TEMP\\poifiles is denied &#xff0c;此错误本文介绍两种解决办法&#xff0c;选择适合你的方法即可&#xff1b;一般.Net程序运行方案二可能比较常用。 解决方案一&#xff1a; 从 IIS 访问文件系统 如果您在浏…

【HarmonyOS NEXT星河版开发学习】小型测试案例09-B站卡片

个人主页→VON 收录专栏→鸿蒙开发小型案例总结​​​​​ 基础语法部分会发布于github 和 gitee上面&#xff08;暂未发布&#xff09; 前言 鸿蒙开发中层叠布局通过Stack容器组件实现了强大的页面层叠和位置定位能力。这种布局方式不仅增强了界面的美观性和功能性&#xff0c…

《Advanced RAG》-10-Corrective Retrieval Augmented Generation (CRAG)

摘要 CRAG 设计了一个轻量级检索评估器&#xff0c;用于评估针对特定查询检索到的文档的整体质量&#xff0c;并使用网络搜索作为改进检索结果的辅助工具。CRAG 可与基于 RAG 的各种方法无缝集成&#xff0c;并提供了一个插件式的解决方案。 CRAG 的主要思想是引入一个检索评估…

前端面试宝典【vue篇】【5】

在前端开发的世界里,每一次面试都是一次机遇,也是一次挑战。 你是否曾因技术深度不够而错失良机? 或是面对最新的技术趋势感到迷茫? 我们的【前端面试宝典】正是为此而来。 由拥有多年一线实战经验的资深工程师亲自授课,结合最新的行业动态与实战案例,旨在全面提升你的技…

Java与Python的跨界融合:打造高效与灵活的编程体验

目录 一、引言 1.1 为什么结合Java与Python 1.2 结合方式概览 二、实现方法详解 2.1 Web服务接口 2.2 命令行调用 三、高级融合方式 3.1 Jython 3.2 GRPC/Protobuf 四、优势与挑战 4.1 优势 4.2 挑战 五、结论 在当今快速发展的软件开发领域&#xff0c;单一编程语…

零售企业中 SRM 系统与开源 AI 智能名片商城系统的协同作用

摘要&#xff1a;本文深入探讨了 SRM 系统在零售企业与上游供应商关系管理中的关键作用&#xff0c;并引入开源 AI 智能名片商城系统&#xff0c;细致分析了两者如何协同助力零售企业优化供应链、提升竞争力。通过阐述 SRM 系统的功能模块及其对零售企业的多方面积极影响&#…