繁体   English   中英

使用解构和递归处理数组的函数的性能提高

[英]Increasing performance of a function which processes an array using destructuring and recursion

我想创建一个函数,该函数将另一个函数和一个数组作为参数,并为数组的每个三个连续元素(例如,第一,第二和第三;第二,第三和第四)调用该函数。 我使用解构和递归实现了它。 但是,我发现它的性能很差–处理大约1000个元素的数组大约需要100毫秒,并占用大量内存。 这是一个代码片段:

 const eachThree = fn => ([first, second, third, ...rest]) => { fn(first, second, third); if (rest.length !== 0) { eachThree(fn)([second, third, ...rest]); } }; const noop = () => {}; const arr = Array(1000).fill(undefined); console.time('eachThree'); eachThree(noop)(arr); console.timeEnd('eachThree'); 

我知道要提高性能,我可以只使用常规的for循环,但是是否可以以某种方式修改此函数以使其更快,同时保持分解和递归?

另外,是否有计划优化JavaScript引擎以使这样的代码运行更快? 尾注优化会解决这个问题吗?

处理1000个元素的数组大约需要100毫秒,并占用大量内存。

显然,其原因是解构和散布语法,该语法创建了2000个数组,平均大小为500个元素。 那不便宜。

我知道要提高性能,我可以只使用常规的for循环,但是是否可以以某种方式修改此函数以使其更快,同时保持分解和递归?

放弃销毁(支持索引,例如@Sylwester的答案)将是最好的解决方案,但实际上还有其他一些事情可以优化:

  • 使用return可以进行尾部调用优化(如果引擎支持的话)
  • 缓存内部函数,而不是一遍又一遍地使用相同的fn重新创建闭包。

const eachThree = fn => {
  const eachThreeFn = ([first, second, third, ...rest]) => {
    fn(first, second, third);
    if (rest.length !== 0) {
      return eachThreeFn([second, third, ...rest]);
    }
  };
  return eachThreeFn;
};

因此,我希望为您和我们着想,您确实需要缩短这200ms的时间,因为这对我而言似乎不是一个现实生活中的问题。 在优化规则中知道:

  1. 配置文件,以便您进行优化。

当涉及到优化时,整洁和风格无法实现。 这意味着您可以放弃递归。 但是,在这种情况下,不是最大的问题就是递归,而是要创建的2n数组。 这是一个稍快的版本:

const eachThree = fn => arr => {
  const maxLen = arr.length-3;
  const recur = (n) => {
    fn(arr[n], arr[n+1], arr[n+2]);
    if (n < maxLen) {
      recur(n+1);
    }
  }; 
  recur(0);
};

现在,ES6具有适当的尾部调用,而Node6已实现了此功能。 当我在那里测试时,它的运行速度比原始代码快400倍。 并不是说您会注意到IRL的更改。

由于您似乎愿意重构代码,因此这是一个非常生动的重写,它可以以大约10倍的速度(使用基准测试方法)执行相同的任务

我想您会欣赏到非常实用的样式

 const drop = (n,xs) => xs.slice(n) const take = (n,xs) => xs.slice(0,n) const slide = (x,y) => xs => x > xs.length ? [] : [take (x,xs)] .concat (slide (x,y) (drop (y,xs))) const eachThree = f => xs => slide (3,1) (xs) .forEach (([a,b,c]) => f (a,b,c)) const noop = () => {} const arr = Array(1000).fill(undefined) console.time('eachThree') eachThree(noop)(arr) console.timeEnd('eachThree') 

使用蹦床可以解决内存使用问题,但是并不能加快代码的速度。 这是一个代码片段:

 const trampoline = fn => { do { fn = fn(); } while (typeof fn === 'function'); }; const eachThree = fn => ([first, second, third, ...rest]) => () => { fn(first, second, third); if (rest.length !== 0) { return eachThree(fn)([second, third, ...rest]); } }; const noop = () => {}; const arr = Array(5000).fill(undefined); console.time('eachThree'); trampoline(eachThree(noop)(arr)); console.timeEnd('eachThree'); 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM