V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
crella
V2EX  ›  程序员

有多少人入门的时候被默认低性能的字符串连接方式坑得不浅的

  •  
  •   crella · 2019-12-14 14:14:12 +08:00 · 4091 次点击
    这是一个创建于 1810 天前的主题,其中的信息可能已经有所发展或是发生改变。

    自己用到 ruby 的字符串连接的时候,从'str1 += str2'号改成'str1 << str2',感觉就像翻身农奴把歌唱一样,速度快了十倍,内存消耗小了约一半……

    本来是联想到 c#的 Stringbuilder,然后上 stackoverflow 看看 ruby 连接字符串时被吐槽的地方,看到了'<<'号,就试一试,效果很好。因为懒得打字,所以我写 Array.push(obj)都改成 Array << obj 的形式了。

    又找到了个比较详细的解释: https://www.xuebuyuan.com/1256522.html

    某些新手教程不深入讲字符串连接。

    18 条回复    2019-12-15 23:20:52 +08:00
    memedahui
        1
    memedahui  
       2019-12-14 14:20:29 +08:00
    快忘光了,随手翻翻手中的汇编指南
    nulIptr
        2
    nulIptr  
       2019-12-14 14:38:24 +08:00 via iPhone
    不要一刀切,很多时候直接用+可以被编译期优化掉,尤其是拼 sql 的时候
    dbpe
        3
    dbpe  
       2019-12-14 14:40:41 +08:00
    emmmm..这些不是应该能被编译器优化掉么....
    Bromine0x23
        4
    Bromine0x23  
       2019-12-14 15:04:52 +08:00
    再本质点的话是因为 a += b 只是 a = a + b 缩写,也就是没有修改原本的 a 对象,而是用生成的新对象替换了 a 的引用
    Raymon111111
        5
    Raymon111111  
       2019-12-14 15:15:49 +08:00
    既然大多数人都用 str1+str2 这种写法, 而且这种写法看起来简洁直观, 那编译器应该对它进行优化

    (就和 java 一样, 单纯的字符串拼接加号是最快的, 除了放在循环里
    maomaomao001
        6
    maomaomao001  
       2019-12-14 15:49:00 +08:00 via Android
    如此简单的事情,居然编译器不能优化? 居然还要手动自己调 ? 应该不会吧
    agagega
        7
    agagega  
       2019-12-14 16:52:32 +08:00 via iPhone
    Ruby 现在不都 Rope 了么?而且这种机会应该可以被优化掉了
    zunceng
        8
    zunceng  
       2019-12-14 17:01:30 +08:00
    @nulIptr 抓到一个拼接 sql 的 大家快去试 sql 注入他的库
    crella
        9
    crella  
    OP
       2019-12-14 17:05:05 +08:00
    @Bromine0x23 你一说我才想起。

    比如 a=1; 10.times {a += 1;}; a.object_id =>23

    已知 1.object_id = 3,2.object_id = 5,则 23=10*2+3。

    真是让人觉得奇怪。
    crella
        10
    crella  
    OP
       2019-12-14 17:22:29 +08:00
    顺便做个笔记吧。

    a=5; a.object_id == 5.object_id => true

    ObjectSpace._id2ref(a.object_id) == 5 => true
    Bromine0x23
        11
    Bromine0x23  
       2019-12-14 19:22:02 +08:00
    @crella 没什么奇怪的,对象 ID 空间就是这么规定的 https://github.com/ruby/ruby/blob/v2_6_5/gc.c#L3258
    zappos
        12
    zappos  
       2019-12-15 02:16:21 +08:00 via Android
    @nulIptr 插值啊,插值是干嘛用的
    crella
        13
    crella  
    OP
       2019-12-15 07:20:17 +08:00
    @zappos 我在 ruby 里面试验,插值法比+=还要慢。

    代码见 https://dpaste.org/T1vR

    我也很早就发现 ruby 确实比其他语言奇怪一些……
    msg7086
        14
    msg7086  
       2019-12-15 07:56:45 +08:00   ❤️ 1
    顺便一提,原本 Matz 是打算在 Ruby 3 里默认冻结字符串常量的,所以当你在旧版本里开启 frozen_string_literal 提前享受这份快乐的时候,是不能对字符串做 << 操作的。不过后来 Matz 后悔了,于是 Ruby 3 不打算默认冻结了……

    另外各方面都比较好的做法是用数组做 StringBuilder,即
    c = ['start']
    10000.times { c << "-con" }
    c = c.join

    这种做法在没开 frozen string 的时候用时只比<<慢 60%,开了 frozen 以后比<<快 5%,比插值和+=都快得多。
    yannxia
        15
    yannxia  
       2019-12-15 09:50:18 +08:00
    以前 JavaBoy 也经常有这样的困扰。
    nulIptr
        16
    nulIptr  
       2019-12-15 12:40:24 +08:00 via iPhone
    @zappos c#里面 string.format 和$插值就是+
    zappos
        17
    zappos  
       2019-12-15 16:52:11 +08:00 via Android
    @nulIptr 但是 string.join 是计算好长度然后分配一个 char* 再拿它初始化 string。很谜。
    ColinZeb
        18
    ColinZeb  
       2019-12-15 23:20:52 +08:00 via iPhone
    @zappos C#里的+貌似等同于 string.concat
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3823 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 10:31 · PVG 18:31 · LAX 02:31 · JFK 05:31
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.