Python 子进程;无法读取 stdout
我有大约50万个文本文件,总共大约7个GB的数据。我正在用Python把它们放进一个sqlite数据库里。我创建了两个表,第一个表是主键和文件的超链接。
第二个表我使用了一个同事用Perl开发的实体提取器。
为了实现这个,我使用了subprocess.Popen()。在这之前,我在每次循环时都打开Perl,但这样做太耗资源,根本没法用。
我需要Perl是动态的,能够在它和我的程序之间来回传递数据,并且在我没有告诉它之前,它不能结束。Perl被修改过,现在它可以接受整个文件的内容作为输入,并在接收到换行符时输出结果。但我在读取数据时遇到了麻烦……
如果我使用communicate,下一次循环时我的子进程就会被终止,导致我出现输入输出错误。如果我尝试使用readline()或read(),程序就会卡住。这里有一些我遇到的不同情况的例子。
这会导致我的系统死锁,我需要强制关闭Python才能继续。
numberExtractor = subprocess.Popen(["C:\\Perl\\bin\\perl5.10.0.exe","D:\\MyDataExtractor\\extractSerialNumbers.pl"], stdout=subprocess.PIPE, stdin= subprocess.PIPE)
for infile in glob.glob(self.dirfilename + '\\*\\*.txt'):
f = open(infile)
reportString = f.read()
f.close()
reportString = reportString.replace('\n',' ')
reportString = reportString.replace('\r',' ')
reportString = reportString +'\n'
numberExtractor.stdin.write(reportString)
x = numberExtractor.stdout.read() #I can not see the STDOUT, python freezes and does not run past here.
print x
这会取消子进程,导致我在下一次循环时出现输入输出错误。
numberExtractor = subprocess.Popen(["C:\\Perl\\bin\\perl5.10.0.exe","D:\\MyDataExtractor\\extractSerialNumbers.pl"], stdout=subprocess.PIPE, stdin= subprocess.PIPE)
for infile in glob.glob(self.dirfilename + '\\*\\*.txt'):
f = open(infile)
reportString = f.read()
f.close()
reportString = reportString.replace('\n',' ')
reportString = reportString.replace('\r',' ')
reportString = reportString +'\n'
numberExtractor.stdin.write(reportString)
x = numberExtractor.communicate() #Works good, I can see my STDOUT from perl but the process terminates and will not run on the next iteration
print x
如果我就这样运行,它会顺利执行所有代码。打印的内容是每个文件项的', mode 'rb' at 0x015dbf08>。
numberExtractor = subprocess.Popen(["C:\\Perl\\bin\\perl5.10.0.exe","D:\\MyDataExtractor\\extractSerialNumbers.pl"], stdout=subprocess.PIPE, stdin= subprocess.PIPE)
for infile in glob.glob(self.dirfilename + '\\*\\*.txt'):
f = open(infile)
reportString = f.read()
f.close()
reportString = reportString.replace('\n',' ')
reportString = reportString.replace('\r',' ')
reportString = reportString +'\n'
numberExtractor.stdin.write(reportString)
x = numberExtractor.stdout #I can not get the value of the object, but it runs through all my files fine.
print x
希望我只是犯了个简单的错误,但有没有办法让我只把一个文件发送给Perl(作为输入),获取输出,然后在循环中重复这个过程,而不需要为每个文件重新打开子进程呢?
1 个回答
考虑使用命令行工具,这样生活会简单很多。
perl extractSerialNumbers.pl *.txt | python load_database.py
别费劲去让Python去启动perl之类的。直接从perl读取结果,然后在Python中处理这些结果就行了。
因为这两个程序是同时运行的,所以通常速度很快,而且会占用很多CPU资源,但你自己写的代码却不需要太多。
在Python程序(load_database.py)中,你可以简单地使用 fileinput
模块来读取从标准输入传来的整个文件。
import fileinput
for line in fileinput.input():
load the row into the database
如果让命令行来处理设置管道的繁琐工作,那么在Python程序中你需要做的就差不多这些了。