侧边栏壁纸
博主头像
一笑痕

仙人之下我无敌,
仙人之上一换一。

  • 累计撰写 67 篇文章
  • 累计收到 7 条评论

五万行日志提字段,三种写法差 4 倍,最快的是最笨的

2026-9-19 / 0 评论 / 4 阅读

五万行日志提字段,三种写法差 4 倍,最快的是最笨的

2.9 毫秒。这是 5 万行日志提两个字段的极限速度,用的不是正则,是 indexOf 手工切。全文围绕一张数据表展开,环境 Node v26.8.1,本机实测,脚本 tools/verify-log-extract-perf.mjs

数据表

A 正则逐行 exec : 5 轮取中位 4.1 ms
B indexOf 手工切: 5 轮取中位 3.1 ms
C split(空格)   : 5 轮取中位 5.3 ms

三种方式找出的 500 行数: A=7143 B=7143 C=0
A 与 B 结果一致: true
A 与 C 结果一致: false
D 位运算累加计数: 5 轮取中位 1.3 ms
E 普通布尔累加  : 5 轮取中位 1.3 ms

D=7143 E=7143 两者相等: true

怎么读这张表

A 和 B 找出的行数一样多(7143 行),结果逐行一致,说明两种写法在语义上等价,比的纯粹是速度。正则没输得很惨,V8 的正则引擎对这种固定模式优化得不错,只慢 32%。

C 是全场最大的教训:5.3 毫秒最慢,还一个都没找对(C=0)。原因在数据里:日志行的字段之间有的用单空格,有的用多空格对齐,split(' ') 切出来的数组错位,按固定下标取字段全取歪了。C 的结果和 A 完全不一致。用 split 前不先看一眼数据的真实分隔符,速度再快也是白算。

D 和 E 是另一组对照。计数 7143 行日志里 level 为 ERROR 的条数,D 用位运算(flags |= 1),E 用普通布尔(flag = true)。1.3 毫秒对 1.3 毫秒,完全打平。这一组的结论和价值刚好相反:位运算在这个量级上没有任何可测量的收益,代码可读性却差一截。写 E 这种,别写 D。

为什么 indexOf 最快

三行日志样本长这样(真实数据的前三行):

2026-09-19T12:00:00.001Z INFO  http 200 /api/users 12ms
2026-09-19T12:00:00.002Z ERROR http 500 /api/orders 87ms
2026-09-19T12:00:00.003Z WARN  http 304 /api/items 3ms

格式完全固定。indexOf 直接跳到已知位置切一刀,正则要多做模式匹配的状态机跳转。数据越规整,正则的抽象越多余。这也是全文最实用的一条:处理机器生成的固定格式日志,先试 indexOf,正则留给格式真的会变的场景。

这张表没覆盖的

只测了 5 万行的规模,单线程,数据全部提前载入内存。文件更大到要流式读、或者日志行里混了多字节中文,数字会变,方向会不会变没实测。另外三个方式都是在同一进程里轮流跑的,缓存 warm 的次序可能有影响,取了 5 轮中位来压这个噪声,但没有做更严格的交叉验证。

    🤞 分享