为何subprocess.Popen调用grep远快于check_output?该如何选型?
为什么用subprocess.Popen()调用grep比subprocess.check_output()快这么多?
嘿,先给你指出一个关键问题:你看到的耗时差异根本不是两种方法的真实性能差距——你的Popen代码其实根本没等grep执行完!这才是耗时差了几千倍的核心原因。
问题出在你的代码里
先看你写的Popen片段:
matched_reads = subprocess.Popen(['grep', match, file], stdout=subprocess.PIPE, env=myenv) mathced_reads = str(matched_reads).splitlines()
subprocess.Popen是非阻塞调用——它启动grep进程后立刻返回一个进程对象,不会等grep把文件处理完。你接下来直接把这个进程对象转成字符串,这根本不是读取grep的输出,只是把进程的描述信息(比如<subprocess.Popen object at 0x...>)拆成了行,完全没处理实际的匹配结果。这也是为什么耗时只有0.002秒:你根本没等grep干活!
而subprocess.check_output是阻塞调用,它会全程等待grep进程执行完毕,把所有匹配结果捕获后才返回,所以5.28秒才是grep处理你的大文件的真实耗时。
正确的Popen用法应该是这样
如果你想用Popen并正确获取grep的输出,必须等待进程结束并读取它的标准输出,比如用communicate()方法:
start = time.time() match = 'chr3' + "[[:space:]]" # 启动进程 proc = subprocess.Popen(['grep', match, file], stdout=subprocess.PIPE, env=myenv) # 等待进程执行完成,同时获取输出 matched_reads, _ = proc.communicate() # 把bytes类型的输出转成字符串,再拆分成行 matched_reads = matched_reads.decode().splitlines() end = time.time() runtime = end-start print("Popen Grep (correct): ", runtime)
这样修改后,Popen的耗时会和check_output差不多,因为它现在会老老实实等grep处理完文件了。
该选哪种方法?
- 如果你只是想简单捕获命令输出,并且希望命令执行出错(比如grep没找到匹配返回非0码)时直接抛出异常,优先选subprocess.check_output()——它封装了启动、等待、捕获输出的全流程,代码更简洁易读,不用自己处理进程等待的逻辑。
- 如果你需要更灵活的控制,比如:
- 边运行grep边读取输出(不用等整个文件处理完)
- 同时处理标准输入/输出/错误流
- 启动进程后先去做别的任务,稍后再处理结果
那可以用subprocess.Popen(),但一定要记得用communicate()或者wait()方法等待进程结束,避免出现逻辑错误。
另外,注意不管用哪种方法,check_output和communicate()返回的都是bytes对象,需要用.decode()转成字符串后再拆分行,这样才能得到你需要的每行字符串。
内容的提问来源于stack exchange,提问作者jy454
相关产品推荐
相关产品推荐

