我把 ripgrep 和 grep 各喂了 4GB 语料,grep 赢了。先说结论,反直觉但复现稳定(2 核 EPYC,热态各 3 轮中位):小文件语料(3.95GB / 10000 文件,平均 400KB)grep -rc 0.28s、rg 默认 0.77s——grep 快 2.8 倍;大文件语料(3.4GB / 100 文件,每个 34MB)rg 默认 0.56s、grep -rc 1.84s——rg 快 3.3 倍。同一台机器、同一个词、同样 4GB 数据,换一种文件分布,胜负直接翻转。这说明"ripgrep 比 grep 快"这句话,和"Rust 比 C++ 快"一样,是省略了前提的断言。rg 快的从来不是"单文件吞吐",而是调度策略:文件够多它才开并行摊掉调度开销,文件够大它才用 SIMD 批量扫。文件又少又碎的时候,它的调度层反而是税。
这篇文章讲四件事:① 本机 4GB 双组语料对照,小文件 grep 赢、大文件 rg 赢的完整数字;②"10MB 内存查 100GB"验的是机制不是字面;③ 快在哪三层(并行调度 / 单线程吞吐 / 默认搜得少),每层挂本机证据;④ 边界三条。机器:AMD EPYC 9354P 2 核切片,ripgrep 14.1.0 / GNU grep 3.11,2026-10-05 实测,每条数字挂命令可复现。
我把 4GB 语料喂了 ripgrep 和 grep,grep 赢了
两组语料,同一台机器、同一个词(needle-7f3a9c,命中 10000 / 3000 行):
# 小文件语料:3.95GB / 10000 文件(平均 400KB)
$ rg -c needle-7f3a9c data/corpus # 0.77s(热态中位)
$ rg -j1 -c needle-7f3a9c data/corpus # 1.06s(强制单核)
$ grep -rc needle-7f3a9c data/corpus # 0.28s(grep 赢 2.8 倍)
# 大文件语料:3.4GB / 100 文件(每个 34MB)
$ rg -c needle-7f3a9c data/corpus-big # 0.56s(rg 赢 3.3 倍)
$ rg -j1 -c needle-7f3a9c data/corpus-big # 0.82s
$ grep -rc needle-7f3a9c data/corpus-big # 1.84s
小文件上 grep 赢 2.8 倍,大文件上 rg 赢 3.3 倍——唯一变量是文件分布,胜负直接翻转。rg 快的不是"单文件吞吐",是调度策略。
"10MB 内存查 100GB"这句话,本机 4GB 语料先验给它
| 语料 |
rg 峰值 RSS |
grep 峰值 RSS |
| 小文件 3.95GB |
9.7MB |
5.0MB(递归口径不同) |
| 大文件 3.4GB |
6.7MB |
4.4MB(单文件 34MB 口径) |
rg 搜 3.95GB 峰值内存 9.7MB,搜 3.4GB 降到 6.7MB——语料量对 RSS 没有单调影响,因为它是流式逐文件处理、不驻留全量。这就是"10MB 查 100GB"的机制来源:内存是 O(文件流缓冲),不是 O(语料总量)。grep 是单进程逐文件递归,RSS 口径不同(递归时每个文件 fork 的子进程单独算),拿 9.7 vs 5.0 直接比不公平——文中如实标注,没做 100GB 外推。
快在哪:拆成三层,每层给本机证据
第一层:并行调度(文件多时回本)
rg 默认线程池 = 2 × ncpu(本机 2 核 → 4 线程池)。小文件语料 10000 个,单文件活只有 400KB,线程池调度 + 结果归并的固定开销摊不到 0.28s 的 grep 头上,所以 rg 慢。大文件语料 100 个,单文件 34MB 足够长,4 线程并行直接线性加速到 0.56s。
验证:rg -j1(强制单核)小文件 1.06s、大文件 0.82s——大文件场景 rg 赢的不是并行,是单线程吞吐(下一层)。
第二层:单线程吞吐(大文件时 SIMD 回本)
rg 默认用 Rust 的 regex 引擎,匹配走内存安全 + 编译期优化;grep 3.11 默认走 GNU regex(非 PCRE2),单线程对 34MB 大文件 1.84s,rg -j1 0.82s——单核下 rg 单线程比 grep 快 2.2 倍。这才是"Rust 快"真正落在大文件上的部分:不是魔法,是 grep 的默认 regex 引擎对长行 / 大文件不是最优路径。
第三层:默认行为(搜得少,不只是搜得快)
rg 默认跳过二进制文件、跳过 .gitignore、跳过隐藏文件(. 开头);输出按文件聚合、颜色高亮、行号;对 UTF-8 强制假设(非 UTF-8 文件直接跳过)。小文件语料里我全部是 .log,三层默认行为都没触发过滤,所以对比是"纯搜索"口径。换成真实代码仓库,rg 的"搜得少"会让它扫的字节数比 grep -r 小一个量级——那一层的优势我本机没单独量化,进"相关阅读"不写正文。
本机数字全表(2 核 EPYC,2026-10-05,热态 3 轮中位)
| 语料 |
rg 默认(2核) |
rg -j1(单核) |
grep -rc(单核) |
胜者 |
| 小文件 3.95GB / 10000 文件 |
0.77s |
1.06s |
0.28s |
grep 2.8x |
| 大文件 3.4GB / 100 文件 |
0.56s |
0.82s |
1.84s |
rg 3.3x |
同机器同词,唯一变量是文件分布。
边界写清楚
- 本机 2 核,rg 线程池是 4(
2 × ncpu),4 线程池在 2 物理核上存在超线程争用,"大文件 rg 快 3.3x"在 4 核+ 机器上会更陡;小文件 grep 赢的幅度会随核数上升缩小
- 热态中位,首轮冷启动(页缓存 miss)rg 小文件首跑 11.7s / grep 16.3s,冷态下两者都打回原形、并行优势消失——"冷启动 rg 慢"和 Headstart 那篇"2 核并行反而慢"是同域现象,跨篇引用
- grep 3.11 默认 regex 引擎不是 PCRE2(
grep -P 才走 PCRE2,我没测);rg 的 regex 是 Rust regex crate,支持子集但不支持回溯——两者匹配能力不对称,纯计时不覆盖"能搜出什么"的维度
那"ripgrep 10MB 查 100GB"到底该不该信
该信机制,不该信数字字面。本机 4GB 语料验出来的是"RSS 不随语料量单调涨"这个 O(流) 特性,9.7MB / 6.7MB 两个点落在同一条平缓曲线上;外推到 100GB 需要更大语料或更多文件数才能复现,本机没做,进"相关阅读"。
流传话里"快"的部分,本机拆成三层验证:并行(大文件回本,3.3x)、单线程吞吐(大文件 2.2x)、搜得少(默认过滤,未量化)。"小文件 grep 赢"这个反直觉结果,是我这次实测里最有用的一个数字——它把"rg 快"从玄学拽回成了"看你的文件分布"的工程判断。
FAQ
ripgrep 真的比 grep 快吗?
看文件分布。本机 4GB 语料:小文件(10000 个)grep 0.28s 比 rg 0.77s 快 2.8 倍;大文件(100 个 34MB)rg 0.56s 比 grep 1.84s 快 3.3 倍。同一台机器同一句话,胜负翻转。
那"10MB 内存查 100GB"怎么来的?
本机 4GB 语料:rg 搜 3.95GB 峰值 RSS 9.7MB、搜 3.4GB 6.7MB——内存不随语料量单调涨(流式逐文件),"100GB"外推本机没做,只验了机制。
rg 单核(-j1)还比 grep 快吗?
大文件快(0.82s vs 1.84s,2.2x),小文件慢(1.06s vs 0.28s)。单核下 rg 赢的是单线程正则引擎,输的是调度层固定开销。
rg 快在哪一层,我该优化什么?
三层:并行调度(文件多时回本)、单线程吞吐(大文件回本)、默认搜得少(代码仓库里扫的字节数直接少一个量级)。文件碎、数量多,rg 调度开销大于收益——这种场景 grep 反而合适。
冷启动会怎样?
页缓存 miss 时并行优势消失:rg 小文件冷跑 11.7s、grep 16.3s,打回原形。热态下才看到文中的 3.3x / 2.8x。和 Headstart 那篇"2 核 -Zthreads 反而慢"同域。
转给那个"rg 就是比 grep 快、不用想了"就开干的同事——你的文件分布决定它快还是慢,这篇把数字量穿了。结论都是:官方 release notes / rg --help 第一屏就写了,读原文比读流传话靠谱。