我只想使用requests.get()
下载一些文件(可能非常大),然后将数据传递给subprocess.Popen
创建的另一个进程的stdin
。示例代码是
In [137]: r = requests.get('http://www.google.com', stream=True)
In [138]: p = subprocess.Popen(['wc'], stdin=r.raw, stdout=subprocess.PIPE)
In [139]: p.communicate()
这不好用。两个问题:
即使网络很好,也需要很长时间才能完成。原因是子进程尝试读取一些数据直到超时。在
$ sudo strace -p 181082
strace: Process 181082 attached
read(0, "", 16384) = 0 <== Here, it takes very long time.
fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
write(1, " 0 0 0\n", 24) = 24
close(0) = 0
close(1) = 0
close(2) = 0
exit_group(0) = ?
+++ exited with 0 +++
传递给stdin
的数据不正确。如您所见,wc
的输出是0 0 0
。
我试图设置r.raw.decode_content = True
,但没有帮助。在
注意:由于get
下载的文件可能非常大,使用r.content
等是不可接受的。在
注意:我使用的是python2.7。在
最简单的方法是使用response.iter_content递增地读取响应正文并将其分块写入进程的stdin:
这样就不会使用
requests
中的任何类似文件的对象,但不需要。请注意,Popen
已经创建了一个类似于文件的对象(即管道),它可以作为process.stdin
访问,您可以使用它在进程到达时将数据实时传递给进程。在目前还不清楚
p.communicate()
在这里做了两件事:wc
写入完毕,它可以输出计数注意:
wc
很适合这里,因为它在打印到stdout
之前消耗了整个stdin
,但是如果您的进程在stdin
之前尝试写入stdout
,那么这种方法可能会死锁。在这种情况下,当进程等待Python从p.stdout
读取数据时,程序可能会冻结在p.stdin.write
上。在为了正确地处理这个问题,您需要分别编写读写线程。
communicate()
为您做了这件事,但它只接受字符串形式的输入,而不接受流或生成器。另一种选择是让进程写入临时文件而不是管道。在相关问题 更多 >
编程相关推荐