在对 Array.prototype.fill() 方法进行一些测试(macOS 上的 Chrome)时,它显然比简单地创建您自己的 慢了将近两倍(如果不是更慢的话) for 循环并填充您的数组。
显然在做类似的事情:
for( var i = 0; i < Array.length; i++) {
A[i] = 0;
}
对比
Array.fill(0);
Array.fill() 方法将花费约 210-250 毫秒来填充大小为 10000000 的数组,而 for 循环将花费约 70-90 毫秒。似乎 Array.fill() 方法可以重写为简单地使用直接循环,因为您始终知道初始索引和目标索引。
let arrayTest = new Array(10000000),
startTime,
endTime;
startTime = performance.now();
arrayTest.fill(0);
endTime = performance.now();
console.log("%sms", endTime - startTime);
arrayTest = new Array(10000000);
startTime = performance.now();
for (let i = 0; i < arrayTest.length; i++){
arrayTest[i] = 0;
}
endTime = performance.now();
console.log("%sms", endTime - startTime);
与我在本地测试时相比,以上实际上显示出更大的差异。
编辑:经过进一步测试后,我现在意识到,当切换到 Firefox 及其真正依赖于引擎时,差异会减少很多。我猜这主要是不同的 JavaScript 引擎优化循环与方法的结果。不过,似乎可以优化 Array.prototype.fill() 中的循环来解决这种差异。
最佳答案
结果与报告一致,即部分 Chrome 是用 JavaScript 编写的,并且依靠运行时分析和优化来提高性能。
我将测试代码打包在一个函数中,以便从可以加载到不同浏览器中的测试页面重复调用(这不是可运行的片段):
<!DOCTYPE html>
<html><head><meta charset="utf-8">
<title>Array.prototype.fill</title>
<script>
Array.prototype.customFill = function( value, start = 0, end = this.length) {
var count = end-start;
if( count > 0 && count === Math.floor(count)){
while( count--)
this[start++]=value;
}
return this;
}
function test() {
let arrayTest,
startTime,
endTime,
arraySize = 1000000;
arrayTest = new Array(arraySize);
startTime = performance.now();
for (let i = 0; i < arrayTest.length; i++){
arrayTest[i] = 0;
}
endTime = performance.now();
console.log("%sms (loop)", endTime - startTime);
arrayTest = new Array(arraySize);
startTime = performance.now();
arrayTest.fill(0);
endTime = performance.now();
console.log("%sms (fill)", endTime - startTime);
arrayTest = new Array(arraySize);
startTime = performance.now();
arrayTest.customFill(0);
endTime = performance.now();
console.log("%sms (custom fill)", endTime - startTime);
}
</script>
</head>
<body>
open the console and click <button type="button" onclick="test()">test</button>
</body>
</html>
可以调整阵列大小以适应所用设备的性能。
Windows 下的 Chrome 浏览器的结果显示循环的性能大幅提升,前两次测试点击测试。在第二次点击时,循环的时间似乎有所改善。在第三次单击时,循环和填充方法似乎都得到了优化,并且运行速度几乎相等,而且速度有所提高。重新加载页面后结果可重复。
我发现这与 Chrome 脚本优化策略一致,与 Chrome 的 Array.prototype.fill 是用 C++ 或类似语言编写的不一致。尽管 Array.prototype.fill.toString() 将函数体报告为“本地代码”,但并未说明它是用什么语言编写的。
为自定义填充方法添加计时,为提高速度而编写,并存储为 Array.prototype.customFill。
Firefox 的计时与用脚本编写的 Array.prototype.fill 一致。 native 实现优于循环,并且通常(但不总是)比自定义填充方法更快。
Chrome 显示的时间也与 Array.prototype.fill 一致,是用某种经过优化的脚本编写的。测试的所有三种填充方法都显示在一两次测试点击后速度有所提高。
但是,自定义填充方法的启动速度比 Chrome 原生版本快十倍以上。您需要将无意义的代码放入自定义方法中,以使其足够慢以接近 native 方法的初始速度。相反,经过优化后, native 方法的速度大约是原来的两倍——用 JavaScript 编写的自定义方法从未得到同样程度的优化。
虽然 Chrome 的 Array.prototype.fill 方法可以用 JavaScript 编写,但似乎需要额外的解释来解释最初的缓慢和注意到的最终性能优化。
关于javascript - 为什么 Array.prototype.fill() 与 `for` 循环相比有如此大的性能差异?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48836753/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我怎样才能完成http://php.net/manual/en/function.call-user-func-array.php在ruby中?所以我可以这样做:classAppdeffoo(a,b)putsa+benddefbarargs=[1,2]App.send(:foo,args)#doesn'tworkApp.send(:foo,args[0],args[1])#doeswork,butdoesnotscaleendend 最佳答案 尝试分解数组App.send(:foo,*args)
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我脑子里浮现出一些关于一种新编程语言的想法,所以我想我会尝试实现它。一位friend建议我尝试使用Treetop(Rubygem)来创建一个解析器。Treetop的文档很少,我以前从未做过这种事情。我的解析器表现得好像有一个无限循环,但没有堆栈跟踪;事实证明很难追踪到。有人可以指出入门级解析/AST指南的方向吗?我真的需要一些列出规则、常见用法等的东西来使用像Treetop这样的工具。我的语法分析器在GitHub上,以防有人希望帮助我改进它。class{initialize=lambda(name){receiver.name=name}greet=lambda{IO.puts("He
我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
通过rubykoans.com,我在about_array_assignment.rb中遇到了这两段代码你怎么知道第一个是非并行赋值,第二个是一个变量的并行赋值?在我看来,除了命名差异之外,代码几乎完全相同。4deftest_non_parallel_assignment5names=["John","Smith"]6assert_equal["John","Smith"],names7end45deftest_parallel_assignment_with_one_variable46first_name,=["John","Smith"]47assert_equal'John
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢