![]()
扫描1亿行JSONL文件,传统grep需要3小时。有人用C语言+线程池,把它压到47秒。这不是魔法,是文件切分策略的暴力美学。
问题本质:为什么grep会卡在IO上
单线程grep的瓶颈从来不是CPU。你看着100%的CPU占用,其实是IO等待的假象——现代SSD的随机读取延迟,能把顺序扫描变成随机漫步。
JSONL(每行一个JSON对象)的麻烦在于:你不能随便切分。在文件中间砍一刀,可能正好落在某个JSON对象内部,解析直接崩溃。
解决方案听起来像作弊:先按字节偏移粗暴切分,再让每个线程"倒车"找换行符。
具体做法是:测量文件总大小(一个系统调用),按线程数均分偏移量。每个工作线程从自己的起点往回扫,直到碰到`\n`,确保段落边界对齐。剩下的就是纯计算——每个线程独立处理自己的文本块,最后合并结果。
这个思路直接借鉴了1BRC(十亿行挑战)的获胜方案。那个比赛比的是处理10亿行温度数据谁最快,冠军用Java做到了1.5秒。核心秘诀一模一样:mmap文件进内存,SIMD指令并行解析,线程池按行边界分治。
ripgrep已经做了,为什么还有人想重写
![]()
评论区有人直接甩出ripgrep(rg)。确实,rg内部就是并行架构,Rust写的,默认开启8线程,对大多数人来说"开箱即用"就够了。
但提问者明确说:我想用C写。
这个选择暴露了一个工程直觉——当文件大到内存装不下,或者需要嵌入现有C代码库时,从头控制每个字节比依赖黑箱更踏实。rg的并行是通用的,你的场景可能是专用的:比如只匹配特定JSON字段,或者匹配结果需要实时流式输出到下游管道。
技术选型永远是个权衡矩阵。GNU parallel的方案也被提到:`parallel --pipe`可以把stdin切成块喂给多个grep进程,`--pipepart`更激进,直接按文件偏移并行。但进程池的上下文切换开销,在C线程池面前像个胖子过独木桥。
有个评论被顶到了前面:「把JSON塞进SQL建索引」。这条建议收获了最多"踩"。
数据导入的时间成本,在"只想扫一遍"的场景下是致命的。 就像为了查一个电话,先把整本黄页录入数据库。索引是写给反复查询的情书,grep是写给一次性扫描的战书。
C实现的两个岔路口
回到C语言的实现路径,摆在面前的是经典的分工问题:自己造轮子,还是借openMP的东风?
![]()
手写线程池的好处是可控。你可以精确决定任务粒度——是按固定行数分包,还是按字节偏移动态平衡。1BRC的冠军方案里有个细节:线程数不是简单的CPU核心数,而是根据L3缓存大小调整,确保工作集不跨NUMA节点。
openMP的路线则是另一种哲学。几行编译指令就能把循环并行化,适合快速验证想法。代价是调试地狱——当某个线程在文件边界处踩了内存,你拿到的core dump是一团模糊的影子。
有个被忽略的细节:正则引擎的选择。PCRE2功能全但慢,Hyperscan(Intel的)用SIMD批量匹配,在固定模式场景下能快10倍。如果你的JSONL查询是固定字段匹配,甚至可以把正则编译成DFA,省掉回溯的麻烦。
文件切分本身也有坑。`\n`换行是Unix的假设,Windows的`\r\n`会让"倒车"逻辑多一个状态判断。更隐蔽的是UTF-8——如果切分点正好落在一个多字节字符中间,字符串匹配会漏掉跨边界的模式。防御性做法是在找换行符时,同时检查UTF-8的continuation byte标记。
工程的最后1%:聚合与输出
并行扫描的终点是结果合并。最简单的办法是每个线程写自己的临时文件,最后cat在一起。但磁盘IO的串行化会吃掉并行带来的收益。
更好的设计是线程本地缓冲区+无锁队列。主线程消费队列,按原始顺序输出。如果结果顺序不重要(大多数grep场景),可以直接并发写标准输出,依赖内核的pipe缓冲机制自然排序。
内存映射(mmap)是另一个加速器。把文件直接映射进虚拟地址空间,省掉read()的系统调用和数据拷贝。代价是page fault的处理延迟,以及大文件可能撑爆虚拟内存。1BRC的选手们在这个点上反复横跳:有人用mmap+madvise顺序预读,有人坚持用传统的read()+自定义缓冲池,实测后者在某些SSD上更快。
最后有个冷知识:现代CPU的向量指令(AVX-512)可以一次比较64字节。把JSONL的文本扫描改成SIMD实现,单线程就能顶原来4-8个线程的吞吐量。但代码可维护性会断崖下跌——你写的是汇编,不是C。
提问者没说的是:这1亿行JSONL从哪来,又要到哪去。是日志分析的中间环节,还是数据迁移的一次性任务?答案会彻底改变技术栈的选择。如果这是你正在面对的问题,你会为了47秒的胜利,跳进C语言和内存管理的深水区吗?
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.