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

mb_*系列函数真是慢啊,这种原生函数有什么好的替代品吗?

  •  
  •   Tianpu · 2015-08-26 19:42:19 +08:00 · 3498 次点击
    这是一个创建于 3159 天前的主题,其中的信息可能已经有所发展或是发生改变。
    翻了一圈资料,为了保持最大兼容性,好像又是不可替代的

    自己维护一个 alphabet ,考虑到多语言,实在是太麻烦了

    有没有人在这方面有过其它的尝试呢?

    比如用正则替代掉?
    第 1 条附言  ·  2015-08-26 23:30:16 +08:00
    实现了个 pcre_stristr

    gist.github.com/anonymous/893a43f87efbd02aa33b

    运行结果如下:

    -----compatibility test-----
    samples count: 1000
    test finished

    -----runtime test-----
    mb_stristr () x1000
    load in 0.08431ms

    pcre_stristr () x1000
    load in 0.00375ms

    time save 95.55%
    第 2 条附言  ·  2015-08-26 23:56:46 +08:00
    如 @vibbow 指出的,应该是大小写相关的函数慢,和 mb_* 本身关系不大
    19 条回复    2015-08-27 09:39:28 +08:00
    jhdxr
        1
    jhdxr  
       2015-08-26 21:12:48 +08:00
    很难想象正则会比 mb_系列函数快。。。另外我很好奇你具体的业务是干什么,居然瓶颈出在这函数上了?
    xzem
        2
    xzem  
       2015-08-26 21:29:34 +08:00 via Android
    正则应该会更慢些
    Tianpu
        3
    Tianpu  
    OP
       2015-08-26 21:35:00 +08:00 via iPhone
    @jhdxr 文本处理呀

    虚拟机上测试
    mb_stristr
    mb_strtolower
    mb_strtoupper
    mb_convert_case
    这几个都是 0.05ms 左右
    对比不带 mb_的只是 0.002ms

    mb_split 好一些,是 0.01ms

    我预感用正则重写至少前面几个可以达到 0.01ms

    正则的坏处是 mb_系列函数毕竟有它的优势,比如同意字符处理,因此重写可能有坑
    Tianpu
        4
    Tianpu  
    OP
       2015-08-26 21:36:33 +08:00 via iPhone
    @xzem 我待会先简单测试下看看, strtoupper 和 stristr
    jfcherng
        5
    jfcherng  
       2015-08-26 22:23:44 +08:00
    同問具體到底如何使用了這些 mb_* 函式
    Tianpu
        6
    Tianpu  
    OP
       2015-08-26 23:35:57 +08:00
    @xzem
    @jhdxr
    @jfcherng

    字符串样本是 0123456789abcdefghijklmnopqrstuvwxyzÁáÀàÂâÄäÃãĄąÆæÇçÉéÈèÊêËëĘęÍíÎîÌìÏïĮįÑñÓóÒòÔôÖöÕõŒœŞşẞßÚúÙùÛûÜüŲųŸÿ0123456789abcdefghijklmnopqrstuvwxyzÁáÀàÂâÄäÃãĄąÆæÇçÉéÈèÊêËëĘęÍíÎîÌìÏïĮįÑñÓóÒòÔôÖöÕõŒœŞşẞßÚúÙùÛûÜüŲųŸÿ

    随机 1000 个短文本测试 stristr ,字符串ß的大小写没有处理,其它兼容性应该不存在了

    pcre 大致是只需要 5%的运行时间

    pcre 内部应该也有个 unicode 的大小写字母表,匹配没有问题,转换大小写好像没什么办法

    除了 mb_convert_case 外,其它 mb_*函数都应该容易改写
    vibbow
        7
    vibbow  
       2015-08-26 23:38:37 +08:00
    C:\Users\vibbo\Desktop>php test.php
    -----compatibility test-----
    samples count: 1000
    test finished

    -----runtime test-----
    mb_stristr () x1000
    load in 0.04488ms

    pcre_stristr () x1000
    load in 0.01255ms

    time save 72.04%
    C:\Users\vibbo\Desktop>
    Tianpu
        8
    Tianpu  
    OP
       2015-08-26 23:43:07 +08:00
    在同一个环境下,不考虑结果的正确性, stristr 的单次运行耗时是 0.0006ms

    比例关系大致是:
    stristr 1
    pcre_stristr 7
    mb_stristr 120

    这个比例和看到的另外测试是一致的,应该是可靠的结果
    vibbow
        9
    vibbow  
       2015-08-26 23:44:06 +08:00
    LZ 犯了一个错误,使用了忽略大小写的函数
    PHP 忽略大小写的函数效率巨慢的
    vibbow
        10
    vibbow  
       2015-08-26 23:45:11 +08:00   ❤️ 1
    之前 csdn 那事件的时候,我试过用 PHP 做全文搜索。

    从 大小写不敏感 切换到 大小写敏感 的函数后

    系统压力能从 CPU 转移到硬盘...
    vibbow
        11
    vibbow  
       2015-08-26 23:47:40 +08:00
    当使用大小写敏感函数后:

    C:\Users\vibbo\Desktop>php test.php
    -----compatibility test-----
    samples count: 1000
    test finished

    -----runtime test-----
    mb_stristr () x1000
    load in 0.01333ms

    pcre_stristr () x1000
    load in 0.02427ms

    time save -82.07%
    Tianpu
        12
    Tianpu  
    OP
       2015-08-26 23:48:40 +08:00
    @vibbow 主要是不想还要检查是不是考虑了大小写

    大小写敏感慢的话 很可能是一脉相承的慢 mb_convert_case 相关的都慢死 其它的只是一般的慢 stristr str_ireplace 这些都应该慢了

    暂时我就使用 mb_*了 等有空 再整理数据改写下
    vibbow
        13
    vibbow  
       2015-08-26 23:49:37 +08:00
    @Tianpu 大小写不敏感的速度和 mb 没关系
    你用 PHP 原生的 strtoupper , stristr 之类的都很慢。
    Tianpu
        14
    Tianpu  
    OP
       2015-08-26 23:53:58 +08:00
    @vibbow 多谢

    很可能找到根源了
    PHP 和大小写相关的函数都是慢的

    可是: stristr, strtoupper,ucwords,strtolower 又似乎是必须的
    vibbow
        15
    vibbow  
       2015-08-26 23:59:49 +08:00
    我之前的做法是:
    做两份文件,一份原始文件,一份全小写的文件。
    搜索的时候,在全小写的文件里搜索,找到 index 后,从原始文件里截取出来。

    就这样...
    Tianpu
        16
    Tianpu  
    OP
       2015-08-27 00:05:02 +08:00
    @vibbow 我只有一次写的需求,其实对速度要求也不是那么敏感

    就是上午做了个自定义函数的自动测试,发现用到 mb_*都是 0.0xms+这个级别的,其它的都是 0.001ms-的时间消耗

    然后就想弄清楚到底怎么回事,可能还是得自己维护个 alphabet ,简单的不长的字符串替换还是很快的,有限的文本总是有更多的办法来提升速度
    realpg
        17
    realpg  
       2015-08-27 09:00:48 +08:00
    @Tianpu
    你想想大小写替换的本质,不就是把字符串进行字母个数各基本 replace 么……
    肯定是倍数量级的速度
    Zzzzzzzzz
        18
    Zzzzzzzzz  
       2015-08-27 09:33:18 +08:00
    mb_和不带 mb_的适用环境不同, mb_考虑到字符集的处理性能当然差了, 连 linux 下面常用的文本处理程序 locale 定义成 C 和 utf8 性能都能差几十到几百倍.
    Zzzzzzzzz
        19
    Zzzzzzzzz  
       2015-08-27 09:39:28 +08:00
    上一段没说完, 你要处理的字符串不涉及其他字符集的话用不带 mb_系列挺好的, 涉及的话乖乖用 mb_, 不然的话可以把下一段保存成 gbk 运行一下看看

    <?php
    var_dump (strpos ("一二", "欢") === false );

    var_dump (mb_strpos ("一二", "欢", 0, "GB18030") === false );
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1025 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 19:17 · PVG 03:17 · LAX 12:17 · JFK 15:17
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.