0

0

JavaScript 中的循环展开?

WBOY

WBOY

发布时间:2024-07-24 13:34:01

|

378人浏览过

|

来源于dev.to

转载

javascript 中的循环展开?

javascript 可能会让人感觉与其运行的硬件非常相隔,但低级思考在有限的情况下仍然有用。

kafeel ahmad 最近发表的关于循环优化的文章详细介绍了许多循环性能改进技术。那篇文章让我思考了这个话题。

过早的优化

为了解决这个问题,这是一种很少有人在 web 开发中需要考虑的技术。此外,过早关注优化可能会使代码更难编写、更难维护。了解底层技术可以让我们深入了解我们的工具和一般工作,即使我们无法直接应用这些知识。

什么是循环展开?

循环展开基本上复制了循环内的逻辑,因此您可以在每个循环期间执行多个操作。在特定情况下,让循环中的代码更长可以使其更快. 通过有意识地以

分组

而不是逐一执行某些操作,计算机可能能够更有效地运行。 展开示例

让我们举一个非常简单的例子:对数组中的值求和。

// 1-to-1 looping
const simplesum = (data) => {
  let sum = 0;
  for(let i=0; i < data.length; i += 1) {
    sum += data[i];
  }
  return sum;
};

const parallelsum = (data) => {
  let sum1 = 0;
  let sum2 = 0;
  for(let i=0; i < data.length; i += 2) {
    sum1 += data[i];
    sum2 += data[i + 1];
  }
  return sum1 + sum2;
};

乍一看这可能看起来很奇怪。我们正在管理更多变量并执行简单示例中不会发生的其他操作。这怎么可能更快?!

衡量差异

我对各种数据大小和多次运行以及顺序或交错测试进行了一些比较。 parallelsum 的性能各不相同,但几乎总是更好,除了非常小的数据大小的一些奇怪结果之外。我使用 runjs 进行了测试,它是基于 chrome 的 v8 引擎构建的。

不同的数据大小给出了

立即学习Java免费学习笔记(深入)”;

非常粗略的

这些结果:

小(< 10k):几乎没有什么区别
  • 中(10k-100k):通常快约 20-80%
  • 大(> 1m):始终快两倍
  • 然后我创建了一个包含 100 万条记录的 jsperf 来尝试跨不同的浏览器。自己尝试一下吧!

chrome 运行 parallelsum 的速度是 simplesum 的两倍,正如 runjs 测试所预期的那样。

safari 与 chrome 几乎相同,无论是百分比还是每秒操作数。

同一系统上的 firefox 对于 simplesum 的表现几乎相同,但 parallelsum 只快了 15% 左右,而不是快两倍。

课游记AI
课游记AI

AI原生学习产品

下载

这种变化让我寻找更多信息。虽然这还不是明确的,但我发现了 2016 年的 stackoverflow 评论,讨论了循环展开的一些 js 引擎问题。这是对引擎和优化如何以我们意想不到的方式影响代码的有趣观察。

变化

我也尝试了第三个版本,它在一次操作中添加了两个值,以查看一个变量和两个变量之间是否存在明显差异。

const parallelSum = (data) => {
  let sum = 0
  for(let i=0; i < data.length; i += 2) {
    sum += data[i] + data[i + 1];
  }
  return sum;
};

简短回答:不。两个“并行”版本在彼此报告的误差范围内。

那么它是怎样工作的?

虽然 javascript 是单线程的,但是当满足某些条件时,底层的解释器、编译器和硬件可以为我们执行优化。

在简单的例子中,操作需要 i 值来知道要获取哪些数据,并且需要更新 sum 的最新值。由于这两者在每个循环中都会发生变化,因此计算机必须等待循环完成才能获取更多数据。虽然对我们来说 i += 1 会做什么似乎是显而易见的,但计算机大多理解“值会改变,稍后再检查”,因此它很难优化。

我们的并行版本为 i 的每个值加载多个数据条目。我们仍然依赖于每个循环的总和,但每个周期我们可以加载和处理两倍的数据。但这并不意味着它的运行速度是原来的两倍

.

更深层次的潜水

为了理解为什么循环展开有效,我们研究计算机的低级操作。具有超标量架构的处理器可以有多个管道来执行同时操作。它们可以支持无序执行,因此彼此不依赖的操作可以尽快发生。对于某些操作,simd 可以同时对多条数据执行一项操作。除此之外,我们开始进入缓存、数据获取和分支预测......

但这是一篇 javascript 文章!我们不会走得那么深。如果您想了解更多有关处理器架构的信息,anandtech 有一些出色的 deep dives。

限制和缺点

循环展开并不是魔法。由于程序或数据大小、操作复杂性、计算机体系结构等原因,会出现限制和收益递减。但我们只测试了一两个操作,现代计算机通常支持四个或更多线程。

为了尝试一些更大的增量,我制作了另一个包含 1、2、4 和 10 条记录的 jsperf,并在运行 macos 14.5 sonoma 的 apple m1 max macbook pro 和运行 windows 11 的 amd ryzen 9 3950x pc 上运行。

一次处理 10 条记录比基本循环快 2.5-3.5 倍,但仅比在 mac 上处理 4 条记录快 12-15%。在 pc 上,我们仍然看到 1 到 2 条记录之间的性能提升了 2 倍,但 10 条记录仅比 4 条记录快 2%,这对于 16 核处理器来说是我无法预测的。

平台和更新

这些不同的结果提醒我们要小心优化。针对您的计算机进行优化可能会在功能较差或只是不同的硬件上产生更糟糕的体验。当开发人员在快速、强大的机器上工作时,较旧或入门级硬件的性能或功能问题是一个常见问题,这是我在职业生涯中多次面临的任务。

对于某些性能规模,目前推出的 hp 入门级 chromebook 配备 intel celeron n4120 处理器。这大致相当于我的 2013 core i5-4250u macbook air。在综合基准测试中,它的性能仅为 m1 max 的九分之一。在那台 2013 款 macbook air 上,运行最新版本的 chrome,

4 记录功能

比 10 记录功能快,但仍然只比单记录功能快 60%!

浏览器和标准也在不断变化。例行的浏览器更新或不同的处理器架构可能会使优化的代码比常规循环慢。当您发现自己进行深度优化时,您可能需要确保您的优化与消费者相关,并且保持相关性. 这让我想起了 nicholas zakas 写的《高性能 javascript》一书,我在 2012 年读过这本书。这是一本很棒的书,包含了很多见解。然而,到 2014 年,书中指出的许多重大性能问题已通过浏览器引擎更新得到解决或大幅减少,我们能够将更多精力集中在编写可维护的代码上。

如果您想保持性能优化的领先地位,请为更改和定期验证做好准备。 过去的教训 在研究这个主题时,我遇到了 2000 年的 linux 内核邮件列表线程,该线程关于删除一些循环展开优化,最终提高了应用程序性能。它包括这个仍然相关的点(强调我的):

最重要的是,我们对什么快、什么慢的直观假设常常是错误的,

特别是考虑到过去几年 cpu 发生了多大的变化。

– theodore ts'o

结论
有时您可能需要从循环中挤出性能,如果您正在处理足够的项目,这可能是您这样做的方法之一。了解此类优化固然很好,但对于大多数工作来说,您并不需要它™。 不过我还是希望你喜欢我的漫谈,也许将来你会记住关于性能优化的考虑因素。 感谢您的阅读!

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
chrome什么意思
chrome什么意思

chrome是浏览器的意思,由Google开发的网络浏览器,它在2008年首次发布,并迅速成为全球最受欢迎的浏览器之一。本专题为大家提供chrome相关的文章、下载、课程内容,供大家免费下载体验。

1079

2023.08.11

chrome无法加载插件怎么办
chrome无法加载插件怎么办

chrome无法加载插件可以通过检查插件是否已正确安装、禁用和启用插件、清除插件缓存、更新浏览器和插件、检查网络连接和尝试在隐身模式下加载插件方法解决。更多关于chrome相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

849

2023.11.06

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

786

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

378

2025.12.24

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

33

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

31

2026.01.21

C# 多线程与异步编程
C# 多线程与异步编程

本专题深入讲解 C# 中多线程与异步编程的核心概念与实战技巧,包括线程池管理、Task 类的使用、async/await 异步编程模式、并发控制与线程同步、死锁与竞态条件的解决方案。通过实际项目,帮助开发者掌握 如何在 C# 中构建高并发、低延迟的异步系统,提升应用性能和响应速度。

105

2026.02.06

C++多线程并发控制与线程安全设计实践
C++多线程并发控制与线程安全设计实践

本专题围绕 C++ 在高性能系统开发中的并发控制技术展开,系统讲解多线程编程模型与线程安全设计方法。内容包括互斥锁、读写锁、条件变量、原子操作以及线程池实现机制,同时结合实际案例分析并发竞争、死锁避免与性能优化策略。通过实践讲解,帮助开发者掌握构建稳定高效并发系统的关键技术。

2

2026.03.16

C++多线程并发控制与线程安全设计实践
C++多线程并发控制与线程安全设计实践

本专题围绕 C++ 在高性能系统开发中的并发控制技术展开,系统讲解多线程编程模型与线程安全设计方法。内容包括互斥锁、读写锁、条件变量、原子操作以及线程池实现机制,同时结合实际案例分析并发竞争、死锁避免与性能优化策略。通过实践讲解,帮助开发者掌握构建稳定高效并发系统的关键技术。

2

2026.03.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 10.8万人学习

Git 教程
Git 教程

共21课时 | 4.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号