为何提取20万行文本首字段时awk速度远快于Python?
为什么awk提取文本字段的速度远快于示例中的Python实现
我有一份包含20万行数据的片段列表,每行数据格式如下:
<field 1> <field2>
为提取每行的第一个字段,最初编写的Python实现脚本如下:
import os import sys jump = open(sys.argv[1],"r") clips = open("clips.list","w") text = jump.readlines() list_of_clips = str() for line in text: clip_to_add = line.split(" ")[0] list_of_clips = list_of_clips + clip_to_add +'\n' with open ('clips.list', 'w') as file: file.write (list_of_clips) jump.close()
相同功能用awk命令(注:原命令存在语法错误,正确写法为awk '{print $1}')执行仅需约1秒,速度远快于上述Python脚本。
速度差距的核心原因
速度差来自两方面:一是示例Python代码存在大量严重的低效设计,二是awk本身就是面向文本流处理高度优化的工具。
- 示例Python代码的低效点:
- 非流式的全量读入开销:调用
readlines()会一次性把20万行数据全部加载到内存生成行列表,额外产生大量内存占用和IO等待成本;而awk默认是逐行流式处理,读入一行、处理一行、输出一行,全程内存占用极低,没有全量加载的额外开销。 - 字符串反复拼接的O(n²)复杂度开销:Python中字符串是不可变对象,循环中反复执行
list_of_clips = list_of_clips + clip_to_add +'\n'时,每次拼接都会生成全新的字符串对象,需要把原有字符串的全部内容复制一遍再追加新内容,20万次循环下来累计的数据复制量会随行数呈平方级增长,这部分是拖慢速度的最主要原因。 - 冗余操作与无效开销:代码一开始就以写模式打开了
clips.list但从未使用,后续又重新通过with块打开同一文件,产生了无意义的系统调用开销;且with块内的写入语句没有正确缩进,实际运行会直接抛出语法错误;split(" ")会把整行按空格完全切分生成包含所有字段的列表,再取第一个元素,额外构造了完全用不到的后续字段对象,浪费内存和计算时间。
- 非流式的全量读入开销:调用
- awk本身的性能优势:
awk是专门为文本处理设计的工具,核心逻辑全部由C编写编译为原生机器码执行,没有Python解释器逐行执行字节码的额外开销;其默认的字段分割逻辑经过高度优化,提取第一个字段时不需要切分整行生成所有字段,只需要定位到第一个分隔符的位置就可以直接截断取出目标内容,处理路径极短;同时awk天生适配流式处理,读写缓冲区的优化是几十年迭代沉淀下来的,文本IO效率非常高。
优化后的Python实现性能可接近awk
只要修正上述低效逻辑,Python处理该任务的速度可以追到和awk同一量级,参考优化版本:
import sys # 逐行流式读写,不加载全量文件到内存 with open(sys.argv[1], "r") as infile, open("clips.list", "w") as outfile: for line in infile: # 定位第一个空格位置直接截断,不做全量切分 split_pos = line.find(" ") outfile.write(line[:split_pos] + "\n" if split_pos != -1 else line)
内容的提问来源于stack exchange,提问作者ZakS
相关产品推荐
相关产品推荐

