为何Vim的:g//d删除命令运行缓慢?与sed性能差距悬殊
:g//d比sed -i '/some_string/d'慢这么多? 这个差异其实很好理解,核心在于Vim和sed的定位、设计目标完全不同:
两者的定位天差地别:Vim是一款交互式文本编辑器,它的核心是服务于人的交互式编辑——要支持光标移动、撤销/重做、语法高亮、代码折叠、插件扩展这些人性化功能,这些都需要Vim在后台维护大量额外的状态信息。而sed是专门为批量流式文本处理设计的工具,它的逻辑是纯线性的:逐行读取输入,匹配规则就处理,然后输出,全程不需要维护任何和交互式操作相关的状态,轻量程度根本不是一个量级。
:g//d的执行逻辑有额外开销:Vim的:global命令其实分两步执行:首先遍历整个缓冲区,标记所有匹配some_string的行;然后再逐个对标记的行执行删除操作。在这个过程中,Vim每做一次标记、每删一行,都可能触发内部的缓冲区更新、显示刷新(哪怕你没直观看到),这些细碎的操作累加起来,处理5000行文件时就会显得很慢。而sed的处理逻辑是“一行过”:读一行,匹配到就跳过不输出,没匹配到就直接写回,全程没有额外的标记、二次遍历步骤,效率自然高得多。Vim的默认配置可能拖后腿:如果你的Vim开启了语法高亮、各种LSP插件、自动格式化检查之类的功能,这些功能会在你执行编辑操作时同步运行,进一步消耗资源。而sed是纯命令行工具,没有这些额外的“负担”,跑起来当然快。
小建议
如果只是做这种批量删除行的操作,sed、awk这类工具本来就是更高效的选择。如果一定要用Vim处理大文件的批量任务,可以试试用vim -n some_file启动(无swap文件模式,减少磁盘IO),或者先临时关闭不必要的功能:
:set nohlsearch nosyntax norelativenumber
再执行:g//d,速度会提升不少。
内容的提问来源于stack exchange,提问作者Melandru's Square

