V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
hupo0
V2EX  ›  JavaScript

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

  •  2
     
  •   hupo0 · 99 天前 · 2644 次点击
    这是一个创建于 99 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

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

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

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

    真要用在后端处理大数据,那还是像 Python 那样用 C 做类库,让 js 调用吧,纯 js 再努力也提升不了太多
    darknoll
        24
    darknoll   98 天前
    没有意义,前端无需注重效率,数据量大了应该是分页之类的,反正 Iterable 对象我都用 for of,我也知道 for 循环速度最快。
    wxsm
        25
    wxsm   97 天前 via iPhone
    从算法角度来说,1 次循环,3 次循环,n 次循环,时间复杂度都是 O(n),并没有实质区别。
    cenbiq
        26
    cenbiq   97 天前
    不禁感慨,C#的 Linq 真是有远见
    hupo0
        27
    hupo0   97 天前
    @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
        28
    cenbiq   97 天前
    @hupo0 用 yield 肯定会产生额外性能损耗嘛。js 是有 Generator 但是我接触下来应用很少,反观 C# IEnumerable 和 IEnumerator 几乎是必不可少的东西,no-stream 类似 rx 管道吧,收集操作最后一次循环执行,无非就是这些方法了。
    不过还是得夸 linq,想当初换到 js 和 java 各种不习惯。
    关于   ·   帮助文档   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2079 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 14:26 · PVG 22:26 · LAX 07:26 · JFK 10:26
    ♥ Do have faith in what you're doing.