1)正如我们所知,map()和reduce()没有副作用。现在,我们在手机上也有多核心。那么,使用它们更有效吗?
2) 另一方面,js在大多数浏览器上只有一个线程可以执行。是否为服务器端脚本编写准备了map()和reduce()?
我今天刚刚用最新的node.js版本在浮点数字上使用map和reduce进行了测试,结果是map和reduct比普通的for循环慢了两个数量级。
var r = array.map(x => x*x).reduce( (total,num) => total+num,0);
~111000ms
var r = 0.0;
array.forEach( (x,i,a) => r += x*x )
~300ms
var r = 0.0;
for (var j = 0; j < array.length;j++){
var x = array[j];
r += x*x;
}
~35ms
编辑:需要注意的是,这种差异在Firefox中要小得多,在未来的Node/Chrome版本中也可能会小得多。
1)
map()和reduce()没有副作用
嗯。您可以很好地实现映射并减少具有副作用的回调。没有什么能阻止它,在JavaScript的当前状态下,它甚至不被认为是一种糟糕的做法。
2)
js在大多数浏览器上只有一个线程可以执行
在今天的所有JS引擎中,只有一个线程,即使它们在服务器端运行时也是如此(事实上,可以有更多线程,但要隔离,不能访问同一个数组)。
因此,没有副作用的事实根本不会使数组修改变得可并行。除了在标准数组上顺序调用回调之外,没有任何JS引擎可以做其他事情。
注意:正如zirak所指出的,有一个不是标准的Mozilla ParallelArray可以帮助进行并行执行。我不知道V8上是否有类似的东西。
只要数组的维数很低(按10的顺序),性能就没有太大差异,但当数组的大小增加到一个很大的值时,使用传统的for循环是一个很好的方法,因为我们只需要循环元素,并在指向时在特定索引处获得值,但在其他方法中,我们不仅要获取索引处的值,还要获取附加信息,如索引(在map中,reduce,forEach)和累加器值(在reduce中)。这些方法需要一个回调函数,它们都占用了大量内存用于回调,这进一步降低了性能速度。
您可以使用以下脚本检查其对正性。只需查看控制台记录的值即可。
var scripts=[];
// GLOBAL variales declaration
var a=[];
function preload() {
for(var i=0;i<100000;i++) a[i]=i;
}
preload();
// TEST function 0
scripts.push(function() {
var sum=0;
a.forEach(function(v) {
sum+=v;
});
//console.log(sum);
});
// TEST function 1
scripts.push(function() {
a.reduce(function(acc,v) {
return acc+v;
});
});
// TEST function 2
scripts.push(function() {
var sum=0;
for(var i=0;i<a.length;i++) {
sum+=a[i];
}
});
// EVALUATION
scripts.forEach(function(f,index) {
var date=new Date();
for(var i=0;i<10000;i++) {
f();
}
console.log("call "+index+" "+(new Date()-date));
});
它很容易被忽视,但获得MapReduce好处的关键是
A) 利用优化的shuffle。通常,map和reduce函数可以用慢速语言实现,只要shuffle(最昂贵的操作)得到了很好的优化,它仍然是快速和可扩展的。
B) 利用检查点功能从节点故障中恢复(但希望您的CPU核心不会出现故障)。
所以最后,map reduce实际上既不是关于map,也不是关于reduce函数。这是关于它周围的框架;即使有糟糕的"map"one_answers"reduce"函数,它也会给你带来良好的性能(除非你在洗牌步骤中失去了对数据集大小的控制!)。
在单个节点上执行多线程map reduce所获得的收益相当低,而且很可能有比map reduce更好的方法来为共享内存架构并行化商店。。。
不幸的是,这些天围绕mapreduce有很多炒作(但了解太少)。如果你查阅原始论文,它会详细介绍"备份任务"、"机器故障"one_answers"局部优化"(对于内存中的单个主机用例来说,这两个都没有意义)。
仅仅因为它有一个"map"和一个"reduce"还不能使它成为"mapreduce)"
如果它有优化的洗牌、节点崩溃和掉队者恢复,那么它就是一个MapReduce