推荐关注
› Meteor
› JSLint - a JavaScript code quality tool
› jsFiddle
› D3.js
› WebStorm
推荐书目
› JavaScript 权威指南第 5 版
› Closure: The Definitive Guide
hupo0

感觉这次写的库能比 js 原生数组方法要快

  •  2
     
  •   hupo0 · Mar 6, 2021 · 5372 views
    This topic created in 2073 days ago, the information mentioned may be changed or developed.

    no-stream 似乎比 js 原生数组方法快

    正在等待被锤的忐忑心理中。

    28 replies  •  2021-03-08 14:10:31 +08:00
    eason1874
    eason1874
    Mar 6, 2021
    1
    不太懂。是循环展开的意思吗?话说现在 JS 不是都要编译了吗,这个在编译时不会自动优化吗?
    hupo0
    hupo0
    OP
    Mar 6, 2021
    2
    @eason1874 应该不叫循环展开,是把多次循环合成一个。只见过 c++ 和 rust 有这类优化,而且对代码有不少限制,可能高级语言要考虑闭包什么的。
    cyberpoint
    cyberpoint
    Mar 6, 2021
    3
    比如程序员为了方便快捷就会写这种代码:const foo = bar.filter(...).map(...).reduce(...)
    这样就会有 3 次遍历,但是其实这些...的过程是可以在一次遍历中完成的
    muzuiget
    muzuiget
    Mar 6, 2021
    4
    明明就是写法问题,这种 [...xxx].map(xxx).filter(xxx).slice(xxx) 我为什么不直接用 for,也是一次循环。
    kkocdko
    kkocdko
    Mar 6, 2021
    5
    是这样的,我记得 rust 的迭代器有这种优化
    hupo0
    hupo0
    OP
    Mar 6, 2021
    6
    @cyberpoint 表达到位
    Jirajine
    Jirajine
    Mar 6, 2021 via Android❤️1
    7
    这个应该不是语言的优化吧,只要方法实现上不返回另一个数组,而是返回一个 lazy evaluation 的 iterator 就可以链式调用多次只遍历一次了。
    muzuiget
    muzuiget
    Mar 6, 2021
    8
    谁白了这种链式求值,就是方便而已,不在乎这点性能损失,真遇到巨大数组,就应该专门写优化代码。
    supermao
    supermao
    Mar 6, 2021
    9
    这种不需要猜,你自己做个 benchmark 不就出来了?
    supermao
    supermao
    Mar 6, 2021
    10
    @supermao 原来已经做了。。。
    Rorysky
    Rorysky
    Mar 6, 2021
    11
    @muzuiget 这不就是 java stream 的写法么
    hupo0
    hupo0
    OP
    Mar 6, 2021
    12
    @Jirajine iterator 转成另一个 iterator,一般是包多一层,该做的“结束检查”还是不会漏的,还是会有额外的性能损耗。实际用 benchmark 测也会发现比较慢。
    jones2000
    jones2000
    Mar 6, 2021❤️1
    13
    太高深了, 看不懂, 学了 2 年 js, 只会用 for(var i=0;i<data.length;++i) .......
    musi
    musi
    Mar 6, 2021❤️1
    14
    纠正一下,这不叫比“ js 原生数组方法要快”
    js 可没让你本来遍历一次的事用三次遍历完成
    geelaw
    geelaw
    Mar 6, 2021 via iPhone
    15
    这个问题和数组遍历几遍没关系,主要区别在于内存分配。

    Array.map 每次都要分配新的数组,可以想象 no-stream 的 map 只是变换迭代器,当然快。当然这不能怪 Array,毕竟功能不同,要写出值得比较的代码可以对 mf 复合自己 map_count 次,再变换成 reducer,然后直接在 data 数组上用 reduce 。

    而且好好写 for 循环不香吗?
    kuunnnn
    kuunnnn
    Mar 6, 2021❤️1
    16
    这不就是延迟计算吗,lazy.js 有做这个的,lodash 好像也有类似的
    shyangs
    shyangs
    Mar 6, 2021
    17
    為什麼不用 lodash 的_.chain()
    molika
    molika
    Mar 6, 2021 via iPhone
    18
    transduce 而已 clojure/clojureScript N 年前就这么玩了 话说 js 的 map reduce 啥的竟然不是惰性的 transduce ? 吃惊
    hupo0
    hupo0
    OP
    Mar 7, 2021
    19
    @shyangs lodash 没用过,我才知道 chain 。看了下源码,他用一个 Wrapper 的抽象,在求值前,把中间的 actions 合成一个。虽然感觉大家想做的事情一样,但实现上效率不那么高。不过 lodash 自带的东西多,容错好,本身不用太注重效率。

    实际 benchmark 跑下来,速度和数组自带的方法差不多,但是内存上应该会更优越。
    hupo0
    hupo0
    OP
    Mar 7, 2021
    20
    @geelaw 比较的代码确实有的斟酌的地方,但是太难找到合适的,就粗暴点只比较了 map 和 reduce 一起用的情况。

    就是不想好好写 for 循环。
    hupo0
    hupo0
    OP
    Mar 7, 2021
    21
    @musi 所以用了似乎,实际上,如果要提高代码的表达,很多时候不会选择把逻辑都挤在一个循环里,至少我是这样的。
    civet
    civet
    Mar 7, 2021 via iPhone
    22
    @molika js 不是天生就是为函数式编程服务的,而是社区各路大神引领了这种潮流,实际上就是底层没实现,写法先出现
    Rocketer
    Rocketer
    Mar 7, 2021 via iPhone
    23
    js 聊性能的意义不是特别大,毕竟主要用途是前端,数组大小不会超过 100 条。相比较而言,节约代码提高开发效率更受欢迎。

    真要用在后端处理大数据,那还是像 Python 那样用 C 做类库,让 js 调用吧,纯 js 再努力也提升不了太多
    darknoll
    darknoll
    Mar 7, 2021
    24
    没有意义,前端无需注重效率,数据量大了应该是分页之类的,反正 Iterable 对象我都用 for of,我也知道 for 循环速度最快。
    wxsm
    wxsm
    Mar 7, 2021 via iPhone
    25
    从算法角度来说,1 次循环,3 次循环,n 次循环,时间复杂度都是 O(n),并没有实质区别。
    cenbiq
    cenbiq
    Mar 8, 2021
    26
    不禁感慨,C#的 Linq 真是有远见
    hupo0
    hupo0
    OP
    Mar 8, 2021
    27
    @cenbiq 看看所谓的 Zero cost abstraction - 刘雨培的文章 - 知乎
    https://zhuanlan.zhihu.com/p/24975048
    吐槽 C# - 刘雨培的文章 - 知乎
    https://zhuanlan.zhihu.com/p/30653282

    参考这两篇回答,17 年的 C#还没有对 linq 进行优化。虽然用迭代器也是相当于只遍历一遍,但是迭代器“调用”迭代器的过程还是会有额外的性能损耗。完美一点的是,能做到跟 C++一样,把迭代器 yield 的逻辑内联到一个循环里。

    想来 no-stream 的做法,是函数调用层面,把"yield"部分通过函数包函数的方式合并到一个循环里。虽然也是有函数调用方面的开销,但目前来看,会比 JS 的 Generator 还节省性能些。

    从现有的 C++和 Rust 的案例来看,其实正道还是 iterator,似乎这样的结构更容易优化。linq 也是在正道上,只是需要引擎对这部分进行优化。与之对应的是 JS 的 Generator 。可惜就是目前他们还很拉胯。
    cenbiq
    cenbiq
    Mar 8, 2021
    28
    @hupo0 用 yield 肯定会产生额外性能损耗嘛。js 是有 Generator 但是我接触下来应用很少,反观 C# IEnumerable 和 IEnumerator 几乎是必不可少的东西,no-stream 类似 rx 管道吧,收集操作最后一次循环执行,无非就是这些方法了。
    不过还是得夸 linq,想当初换到 js 和 java 各种不习惯。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   4119 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 66ms · UTC 06:06 · PVG 14:06 · LAX 22:06 · JFK 01:06
    ♥ Do have faith in what you're doing.