如何百倍加速 Lo-Dash?引入惰性计算
原文:How to Speed Up Lo-Dash ×100? Introducing Lazy Evaluation.
作者: Filip Zawada
译文:如何百倍加速 Lo-Dash?引入惰性计算
译者:justjavac
我一直以为像 Lo-Dash 这样的库已经不能再快了,毕竟它们已经足够快了。
Lo-Dash 几乎完全混合了各种 JavaScript 奇技淫巧(YouTube)来压榨出最好的性能。
但似乎我错了 - 其实 Lo-Dash 可以运行的更快。
你需要做的是,停止思考那些细微的优化,并开始找出更加适用的算法。
例如,在一个典型的循环中,我们往往倾向于去优化单次迭代的时间:
var len = getLength(); for(var i = 0; i len; i++) { operation(); // - 10毫秒 - 如何优化到9毫秒?! }
代码说明:取得数组的长度,然后重复执行 N 遍 operation() 函数。译注 by @justjavac
但是,这(优化 operation() 执行时间)往往很难,而且对性能提升也非常有限。
相反,在某些情况下,我们可以优化 getLength() 函数。
它返回的数字越小,则每个 10 毫秒循环的执行次数就越少。
这就是 Lo-Dash 使用惰性计算的思想。
这是减少周期数,而不是减少每个周期的执行时间。
让我们看看下面的例子:
function priceLt(x) { return function(item) { return item.price }; var gems = [ { name: Sunstone, price: 4 }, { name: Amethyst, price: 15 }, { name: Prehnite, price: 20 }, { name: Sugilite, price: 7 }, { name: Diopside, price: 3 }, { name: Feldspar, price: 13 }, { name: Dioptase, price: 2 }, { name: Sapphire, price: 20 } var chosen = _(gems).filter(priceLt(10)).take(3).value();
代码说明:gems 保存了 8 个对象,名字和价格。priceLt(x) 函数返回价格低于 x 的所有元素。译注 by @justjavac
我们把价格低于 10 美元的前 3 个 gems 找出来。
常规 Lo-Dash 方法(严格计算)是过滤所有 8 个 gems,然后返回过滤结果的前 3 个。
不难看出来,这种算法是不明智的。
它处理了所有的 8 个元素,而实际上我们只需要读取其中的 5 个元素就能得到我们想要的结果。
与此相反,使用惰性计算算法,只需要处理能得到结果的最少数量就可以了。
如图所示:
我们轻而易举就获得了 37.5% 的性能提升。
但是这还不是全部,其实很容易找到能获得 1000 倍以上性能提升的例子。
让我们一起来看看:
// 99,999 张照片 var phoneNumbers = [5554445555, 1424445656, 5554443333, … ×99,999]; // 返回包含 "55" 的照片 function contains55(str) { return str.contains("55"); // 取 100 张包含 "55" 的照片 var r = _(phoneNumbers).map(String).filter(contains55).take(100);
在这个例子中,map 和 filter 用来处理 99,999 个元素。
不过我们只需要它的一个子集就可以得到想要的结果了,例如 10,000 个,
性能提升也是非常大的(基准测试):
惰性计算带来了另一个好处,我称之为 "Pipelining"。
它可以避免链式方法执行期间创建中间数组。
取而代之,我们在单个元素上执行所有操作。
所以,下面的代码:
var result = _(source).map(func1).map(func2).map(func3).value();
将大致翻译为如下的常规 Lo-Dash(严格计算)
var result = [], temp1 = [], temp2 = [], temp3 = []; for(var i = 0; i source.length; i++) { temp1[i] = func1(source[i]); for(i = 0; i source.length; i++) { temp2[i] = func2(temp1[i]); for(i = 0; i source.length; i++) { temp3[i] = func3(temp2[i]); result = temp3;
如果我们使用惰性计算,它会像下面这样执行:
var result = []; for(var i = 0; i source.length; i++) { result[i] = func3(func2(func1(source[i]))); }
不使用临时数组可以给我们带来非常显著的性能提升,特别是当源数组非常大时,内存访问是昂贵的资源。
和惰性计算一起使用的是延迟执行。
当你创建一个链,我们并不立即计算它的值,直到 .value() 被显式或者隐式地调用。
这种方法有助于先准备一个查询,随后我们使用最新的数据来执行它。
var wallet = _(assets).filter(ownedBy(me)) .pluck(value) .reduce(sum); $json.get("/new/assets").success(function(data) { assets.push.apply(assets, data); // 更新我的资金 wallet.value(); // 返回我钱包的最新的总额 });
在某些情况下,这样做也可以加速执行时间。我们可以在前期创建复杂的查询,然后当时机成熟时再执行它。
Wrap up懒惰计算并不是行业里的新理念。它已经包含在了许多库里面,例如 LINQ、Lazy.js 等等。我相信 Lo-Dash 和这些库最主要的区别是,你可以在一个更新的、更强大的引擎里面使用原有的 Underscore API。不需要学习新的库,不需要修改代码,只是简单升级。
但是,即使你不打算使用 Lo-Dash,我希望这篇文章启发了你。
现在,当你发现你的应用程序存在性能瓶颈,不要仅仅是去 jsperf.com 以 try/fail 风格优化它。
而是去喝杯咖啡,并开始考虑算法。
最重要的是创意,但良好的数学背景会让你如鱼得水(book)。祝你好运!
阿里云函数计算——优势 阿里云函数计算——优势自制脑图, 函数计算构建业务系统,用户不再需要考虑服务器相关的问题,由此获得了相当明显的优势。
Laravel 8 新特性之:迁移压缩、任务批处理、速率限制优化 Laravel 8 通过引入 Laravel Jetstream,模型工厂类,迁移压缩,队列批处理,改善速率限制,队列改进,动态 Blade 组件,Tailwind 分页视图, 时间测试助手,artisan serve 的改进,事件监听器的改进,以及各种其他错误修复和可用性改进,对 Laravel 7.x 继续进行了改善。
排序优化:如何实现一个通用的、高性能的排序函数? 如何选择合适的排序算法? 如果要实现一个通用的、高效率的排序函数,我们应该选择哪种排序算法?我们先回顾一下前面讲过的几种排序算法。
蚂蚁图计算正式升级为TuGraph,查询效率提升10倍!兼容性更强 蚂蚁集团“大规模图计算系统GeaGraph”正式升级为TuGraph ,并完成了产品3.0版本的迭代。迭代后的版本查询效率提升10倍,兼容性更强。
速度高达百万帧/秒,颜水成团队开源RL环境并行模拟器,大幅节省CPU资源 在强化学习(RL)智能体模拟训练中,环境高速并行执行引擎至关重要。最近,新加坡 Sea AI Lab 颜水成团队提出一个全新的环境模拟并行部件 EnvPool,该部件在不同的硬件评测上都达到了优异的性能。
推理速度提升29倍,参数少1/10,阿里提出AdaBERT压缩方法 作为当前最佳的自然语言处理模型,BERT 却存在规模大、成本高和实时性差等缺点。为了能在实际应用中部署这种技术,有必要对 BERT 进行压缩。此前机器之心就已经介绍了几种来自不同研究机构的压缩方案,参阅《内存用量 1/20,速度加快 80 倍,腾讯 QQ 提出全新 BERT 蒸馏框架,未来将开源》和《AAAI 2020 | 超低精度量化 BERT,UC 伯克利提出用二阶信息压缩神经网络》。
迷渡 互联网打杂工。曾翻译《JavaScript Quirks》,正在出版《代码之谜》。JSON API 中文规范维护者,Flarum 中文社区创始人。平时混迹于 GitHub,参与众多开源项目,Star 数位列全球前 100 名。
相关文章
- MySQL explain 中的 rows 究竟是如何计算的?
- AI本质就是“暴力计算”?看华为云如何应对算力挑战
- 计算属性
- java实现蔬菜价格计算
- 借力函数计算 FC,HEROZ 打造专业级 AI 日本将棋服务
- 函数计算|如何使用层解决依赖包问题?
- 跨越行业绊脚石,阿里云函数计算发布 7 大技术突破
- 当 Kubernetes 遇到机密计算,阿里巴巴如何保护容器内数据的安全?
- 迁移 Spring Boot 到函数计算
- Serverless 解惑——函数计算如何安装字体
- 开发函数计算的正确姿势——网页截图服务
- 物联网、云计算、大数据、人工智能概念如何区分
- 物联网、云计算、大数据、人工智能怎么区分,又有何关系
- SPSS详细教程:OR值的计算
- 【阿里云资讯】如何让云计算安全变得更“聪明”
- Centos7安装部署openstack--nova计算服务(计算节点)
- Open3D (C++) 计算点云的均值与标准差
- C#计算两个时间的差
- 案例解读华为隐私计算产品TICS如何实现城市跨部门数据隐私计算
- Linux环境下如何计算CPU占用率
- 如何计算边缘计算的成本
- VB编程:Const自定义常量计算圆面积-2
- 华为FusionCompute之计算虚拟化
- 云计算|OpenStack|社区版OpenStack安装部署文档(四 --- 镜像服务glance安装部署---Rocky版)
- 用户画像标签数据开发之标签权重计算
- 【pandas】教程:6-如何计算摘要统计
- [ 云计算 | Azure ] Chapter 03 | 描述云计算运营中的 CapEx 与 OpEx,如何区分 CapEx 与 OpEx
- [ 华为云 ] 云计算中Region、VPC、AZ 是什么,他们又是什么关系,应该如何抉择