我想计算一个大型.fastq文件(5900万行)中大约500个模式的出现。这些模式都正好是20个字符长。
在Unix中,这很简单:
grep -F -o -f patterns.txt big_file.fastq | sort | uniq -c
但是,我希望避免编写临时模式文件,所以我使用python的子进程库创建了一个管道:
from subprocess import Popen, PIPE, STDOUT
p1 = Popen(["grep", "-F", "-o", "-f", "-", "big_file.fastq"], shell = False, stdin = PIPE, stdout = PIPE, stderr= STDOUT)
p2 = Popen(["sort"], shell = False, stdin = p1.stdout, stdout = PIPE, stderr = STDOUT)
p3 = Popen(["uniq", "-c"], shell = False, stdin = p2.stdout, stdout = PIPE, stderr = STDOUT)
然后我在此上调用communication(),提供一个编码的类似于io.StringIO文件的对象作为输入(我使用'-'将其传递给grep命令:]
import io
patterns_file = io.StringIO("\n".join(patterns_list))
p3.communicate(input = patterns_file.read().encode('utf-8'))[0]
当我像这样在uniq上调用communication()时,这可以正常工作。
但是,在测试时,我在管道的第一部分错误地将其称为:
p1.communicate(input = patterns_file.read().encode('utf-8'))[0]
这给了我完全错误的输出,包括比预期的20个字符短或长的匹配。
我不明白为什么会这样。不会在p1上仅调用管道的该部分而忽略其余部分吗?删除p2和p3会使p1正确grep。我觉得我缺少Popen的工作方式。
感谢您的任何帮助。
实例化Popen
对象时,它们所引用的子过程将立即启动。因此,即使仅在communicate()
上调用p1
,p2
和p3
也正在运行。
为什么这很重要?因为p2
仍将其stdin连接到p1
正在向其写入输出的FIFO!
如果在您要求Python程序读取相同内容的同时,sort
上的p2
操作仍在读取内容,则最终将p1
的输出分配给它们。可以预计会出现热闹。