微观平台

我必须在团队内部进行绩效讨论。 由于执行简单的PR,我开始了2周的黑暗javascript旅程。 为了节省您很多痛苦和令人沮丧的问题,我在这篇非常长的文章中总结了我的研究。 我尽力向您展示了思路,但是如果您不关心细节,可以跳到TL; DR部分的结尾。

#冒险之旅

一切都从Github上的简单Pull Request开始。 这是一个javascript文件,我让您阅读:

综上所述,我们团队的工程师使用以下代码编写了一个单行代码,以检查该值是否有效:

['valid_value1' , 'valid_value2' ].includes(value);

另一个建议改为使用“性能改进”:

const VALID_VALUES = new Set ([ 'valid_value1' , 'valid_value2' ]);
VALID_VALUES.has(value);

争论是关于复杂性的说法,即我们正在从O(N)转向O(1)。 PR的作者开始争辩说,这不是一种改进,因为从数组创建Set的时间为O(N)。

免责声明,经过10年的发展,我对此表示了强烈的评价 就性能而言,它并不重要! 这称为微优化,它们不会对网络开发产生任何影响(对于视频游戏而言并非如此)。 因此,我利用我的经理权限停止了讨论。

#追求真理

我本可以忘掉这次谈话,然后回到我的生活。 但是我担心它会再次发生。 确实,我在职业生涯中注意到,技术团队不喜欢经理为他们做决定。 开发人员想了解原因。 因此,我不得不彻底解决这个问题,然后我开始深入研究……

作为每个程序员,我开始谷歌搜索以寻找基准。 JSPerf是一个很好的资源。 它列出了数百个基准,仅用于比较阵列和设置。 结果不是我所期望的。

两种最受欢迎​​的测试得出相反的结论。 在实验(A)中, array.includes()set.has()更快,但在实验(B)中则没有。

#基准:盟友还是敌人?

他们得出不同结论的原因是,这两个基准测试实际上并没有测试同一件事。 你能发现问题吗?

实验(A):

// SETUP
const keys = [ 'build' , 'connected' , 'firmware' , 'model' , 'status' ]
const set = new Set (keys);
// RUN
const randomKey = keys[ Math .floor( Math .random() * keys.length)];
keys.includes(randomKey) // --> Faster
set.has(randomKey)

实验(B):

// SETUP
var keys = [...Array( 512 )].map( ( _, index ) => String .fromCharCode(index + 32 ));
var set = new Set (keys);
// RUN
const randomKey = String .fromCharCode(~~( Math .random() * keys.length * 2 ) + 32 );
keys.includes(randomKey)
set.has(randomKey) // --> Faster

它们是2个主要区别:

  • 实验(A)中只有5个项目,而(B)中有512个项目。
  • 实验(A)仅测试命中 (即,值在数组中时)。 作为(B)测试命中率和未命中率

对于阵列,未命中显然较慢,因为这是最坏的情况。 您必须遍历所有项目才能知道该元素不存在! 您正在尝试将最佳情况下的复杂度与平均复杂度进行比较。 那是我的第一个艰难的教训。

不要相信基准!

#统治所有人的基准?

如我们所见,数组的大小将使性能有所不同。 我想了解什么是门槛。 set何时开始变得比array更有效?

作为大多数开发人员,我认为我可以通过编写自己的代码来解决这个难题。 我专注于.has().includes()因此我自愿将Set的构造从基准中排除。

// SETUP - not included in the perf measure.
var SIZE = 1000 ;
var GLOBAL_ARRAY = [];
for ( var i = 0 ; i < SIZE; i++) {GLOBAL_ARRAY.push( 'key_' + i);
}
var GLOBAL_SET = new Set (GLOBAL_ARRAY);
var LAST_KEY = 'key_' + (SIZE - 1 );var suiteHasVsIncludes = new Benchmark.Suite;

// BENCHMARK on MISS
GLOBAL_ARRAY.includes( 'key_unknown' );
GLOBAL_SET.has( 'key_unknown' );// BENCHMARK on HIT - WORSE CASE SCENARIO
GLOBAL_ARRAY.includes(LAST_KEY);
GLOBAL_SET.has(LAST_KEY);// BENCHMARK on HIT - BEST CASE SCENARIO
GLOBAL_ARRAY.includes( 'key_0' );
GLOBAL_SET.has( 'key_0' );

不出所料,使用Set进行查找的时间不会随Size改变太多,因为它的复杂度应为O(1)。 直到5 000,阵列中未命中的成本是线性的(由于X轴的对数刻度,很难看到)。 到目前为止,它与复杂性保持一致,因为我们必须遍历所有项O(N)。 但是,此后出现了巨大的下降。

总而言之,如果仅比较set.has()array.includes()直到SIZE为5000,则数组的执行速度是x8倍,而100000 set.has()则是x10K倍。

再一次,不要相信我自己的基准 。 我没有比其他人更好。 例如,我使用相同的密钥,如果幕后有某种缓存机制该怎么办? 我还意识到性能测试在本地计算机上运行时并不可靠。

由于您不在受控环境中,因此许多进程都在争夺CPU。 连续运行两次可能会有不同的结果(尤其是如果您在后台收听Spotify的话)。 我尝试在本地计算机上运行相同的代码10次,两次尝试之间的差异高达x3。

Try 1: array.includes() x 27,033 ops/sec ±41.13% (82 runs sampled)
Try 2: array.includes() x  9,286 ops/sec ±15.05% (83 runs sampled)

我使用的Benchmark.js库实际上告诉您要小心。 82次运行之间的差异为±41.13%。 它非常可疑,您可能应该放弃此运行。

#剩下的障碍

我首先对这个结果感到满意。 这与我对复杂性的理解保持一致。 array搜索为O(N),而set在哈希表中使用O(1)查找。

有一件事仍然困扰着我。 当SIZE <5000时, array.includes()的性能比set.has()好8倍

我无法忍受这种不连贯性,如何解释较小的Array实际上比Set更好。

#洞穴:在黑暗中更进一步

我开始在互联网上闲逛,发现这篇文章: 优化哈希表:隐藏哈希码 。

“ Set,Map,WeakSet和WeakMap都在后台使用哈希表。 哈希函数用于将给定键映射到哈希表中的位置。 哈希码是在给定键上运行此哈希函数的结果。

在V8中,哈希码只是一个随机数 ,与对象值无关。 因此,我们无法重新计算它,这意味着我们必须存储它。”

当我阅读最后一行时,我简直不敢相信。 在javascript中,哈希码不是哈希函数的结果,而是随机数? 为什么将其称为哈希表? 我完全迷路了。 然后我想通了。

让我们以两个玩家为例:

var player1 = {name : "Alice" ,score : 87
};
var player2 = {name : "Bob" ,score : 56
}
var set = new Set ();
set.add(player1);
set.add(player2);
player2.score = 66 ;
set.has(player2) // -> true

在Javascript中, 对象是可变的 ,例如,分数可以更改。 因此,我们不能使用对象内容来生成唯一的哈希。 如果鲍勃提高自己的分数,哈希将有所不同。 而且,由于垃圾收集器会移动对象,因此无法使用该存储位置。 这就是为什么它生成与对象一起存储的随机数的原因。 (1)

other那What about other language?
Java的实现OpenJDK 7和OpenJDK 6均使用随机数,如以下文章中所述,默认hashCode()如何工作? (2)

Python ,您根本无法哈希(某些)可变对象:

mylist = []
d = {}
d[mylist] =1
Traceback (most recent call last):File "<stdin>" , line 1 , in <module>TypeError: unhashable type: 'list'

那是第一个启示,哈希函数在理论上和实践上实际上是两件事。 这可以解释性能差异。 但是请稍等,基准测试的代码为:

GLOBAL_SET.has('key_0' );

键不是可变对象,它是string ,Javascript中不变的原始数据类型! (3)

微观平台_微观优化:不要迷失在兔子洞中相关推荐

  1. 微观平台_不再受到微观管理

    微观平台 Organisations spend vast amounts of time and resources on hiring smart, talented and self-motiv ...

  2. rails db 查询优化_如何优化查询以解决Rails中常见的可伸缩性瓶颈

    rails db 查询优化 by Usama Ashraf 通过Usama Ashraf 如何优化查询以解决Rails中常见的可伸缩性瓶颈 (How to optimize your queries ...

  3. 将不同数据存储到数据库中_如何将数据存储在兔子洞中

    将不同数据存储到数据库中 Starting with databases and venturing into how the physical components of a computer st ...

  4. 学习【瑞吉外卖⑪】SpringBoot单体项目_项目优化

    若文章内容或图片失效,请留言反馈.部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 本人写这篇博客旨在制作学习笔记,巩固知识.同时方便个人在线阅览,回顾知识. 这篇博客中主要对应[瑞吉外卖项 ...

  5. 论文研读笔记_基于优化的SVM心音信号分类算法的研究

    论文研究_基于优化的SVM心音信号分类算法的研究 先存起来,持续更新 摘要 心音信号采集易混入杂音,影响判断: 经验式模态分解算法分析特征分布:心音信号集中于低频.噪音集中于高频: 利用切比雪夫滤波器 ...

  6. 获取了网站源码有什么用_环保做推广用什么平台_广告投放-多网站信息推广

    环保做推广用什么平台_广告投放-多网站信息推广 讯呱呱(深圳)网络科技有限公司成立于2020-06-18,法定代表人为刘宪玲,注册资本为101万元,统一社会信用代码为91440300MA5G8KKX6 ...

  7. 基于WF设计业务流程平台_权限在流程模板外部映射

    基于WF设计业务流程平台_权限在流程模板外部映射 前面的几篇文章我介绍了一种权限与流程模板相结合的设计方式,今天我介绍一种权限在流程模板外部映射的计方式. 限在流程模板外部映射,主要的实现思路是: 在 ...

  8. 分类数据显示功能_缓存优化

    分类数据显示功能_缓存优化 问题:如何使用redis按照分类数据的id进行排序存储 *数据库表有cid和cname两个字段 1.Service层代码如下: public List<Categor ...

  9. Unity3d面向英特尔 x86 平台的 Unity* 优化指南: 第 2 部分

    目录 优化 脚本优化 脚本视锥剔除和协同例程 智能内存管理 缓存频繁使用的对象和组件 使用 Unity 物理系统的最佳实践 禁用完全透明对象 返回至教程第 1 部分: 面向英特尔 x86 平台的 Un ...

最新文章

  1. 使用PLP特征训练crnn语音分类
  2. SpringBoot(十二)_springboot整合PageHelper
  3. Android如何优雅地防止Bean类混淆
  4. HDU - 6959 zoto 莫队 + 值域分块
  5. 深度解析开源推荐算法框架EasyRec的核心概念和优势
  6. Lineageos14 20180525更新
  7. 还在维护吗_你的模具生锈了吗?来了解一下这些防锈维护事项
  8. 裁员潮来袭!IT行情雪崩之下,我靠它竟能逆向突破职业危机
  9. 什么是运行时Runtime、运行时库Runtime Library、运行时环境Runtime environment
  10. 计算机无法安装VC2015,win7系统vc++2015一个或多个问题导致了安装失败的处理步骤...
  11. python课设参考文献_Python课程设计任务书
  12. mac下搭建stm32开发环境
  13. 计算机病毒是指源程序还是特殊小程序,2015年9月计算机一级考试Msoffice上机模拟题(五)...
  14. java计算机毕业设计高校疫情管理源程序+mysql+系统+lw文档+远程调试
  15. 以下哪些是微型计算机,2017版计算机试题及答案
  16. 奔腾的芯——英特尔公司
  17. 最短路径 floyd最小环 洛谷2738 篱笆回路 网上题解
  18. GUI素材-FLASH模板集
  19. Oracle获取本年,本月,下月,上月 第一天或最后一天日期
  20. 假币问题(八枚硬币及n枚硬币)

热门文章

  1. 易语言 闹钟程序和播放音乐
  2. 商品房买卖认购书的法律效力如何?
  3. ajax 遇到重定向,ajax 重定向跨域问题
  4. 计算机应用技术读后感1500,计算机应用文摘读后感1000字
  5. NVIDIA RTX A6000/RTX3090/3080/3070深度学习训练/GPU服务器硬件配置推荐2021
  6. html设置文本框后面加符号,将HTML文件读入文本框会将撇号和项目符号转换为?...
  7. useradd 和 adduser 到底用哪个 区别是什么 adduser的perl脚本内容
  8. RobotStudio软件:ABB机器人输送带跟踪虚拟仿真操作方法
  9. 周公解梦数据库(完整版:含9000多条数据)
  10. 电子商务网站系统分析与设计