Python Popen communicate 和wait使用上的区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python Popen communicate 和wait使用上的区别相关的知识,希望对你有一定的参考价值。

参考技术A 简单说就是,使用subprocess模块的Popen调用外部程序,如果stdout或stderr参数是pipe,并且程序输出超过操作系统的pipesize时,如果使用Popen.wait()方式等待程序结束获取返回值,会导致死锁,程序卡在wait()调用上。ulimit-a看到的pipesize是4KB,那只是每页的大小,查询得知linux默认的pipesize是64KB。看例子:#!/usr/bin/envpython#coding:utf-8#yc@2013/04/28importsubprocessdeftest(size):print'start'cmd='ddif=/dev/urandombs=1count=%d2>/dev/null'%sizep=subprocess.Popen(args=cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,close_fds=True)#p.communicate()p.wait()print'end'#64KBtest(64*1024)#64KB+1Btest(64*1024+1)首先测试输出为64KB大小的情况。使用dd产生了正好64KB的标准输出,由subprocess.Popen调用,然后使用wait()等待dd调用结束。可以看到正确的start和end输出;然后测试比64KB多的情况,这种情况下只输出了start,也就是说程序执行卡在了p.wait()上,程序死锁。具体输出如下:startendstart那死锁问题如何避免呢?官方文档里推荐使用Popen.communicate()。这个方法会把输出放在内存,而不是管道里,所以这时候上限就和内存大小有关了,一般不会有问题。而且如果要获得程序返回值,可以在调用Popen.communicate()之后取Popen.returncode的值。结论:如果使用subprocess.Popen,就不使用Popen.wait(),而使用Popen.communicate()来等待外部程序执行结束。Popen.wait()¶Waitforchildprocesstoterminate.Setandreturnreturncodeattribute.WarningThiswilldeadlockwhenusingstdout=PIPEand/orstderr=PIPEandthechildprocessgeneratesenoughoutputtoapipesuchthatitblockswaitingfortheOSpipebuffertoacceptmoredata.Usecommunicate()toavoidthat.Popen.communicate(input=None)¶Interactwithprocess:Senddatatostdin.Readdatafromstdoutandstderr,untilend-of-fileisreached.Waitforprocesstoterminate.Theoptionalinputargumentshouldbeastringtobesenttothechildprocess,orNone,ifnodatashouldbesenttothechild.communicate()returnsatuple(stdoutdata,stderrdata).Notethatifyouwanttosenddatatotheprocess’sstdin,youneedtocreatethePopenobjectwithstdin=PIPE.Similarly,togetanythingotherthanNoneintheresulttuple,youneedtogivestdout=PIPEand/orstderr=PIPEtoo.NoteThedatareadisbufferedinmemory,sodonotusethismethodifthedatasizeislargeorunlimited.subprocess的两种方法:1)如果想调用之后直接阻塞到子程序调用结束:Dependingonhowyouwanttoworkyourscriptyouhavetwooptions.Ifyouwantthecommandstoblockandnotdoanythingwhileitisexecuting,youcanjustusesubprocess.call.#startandblockuntildonesubprocess.call([data["om_points"],">",diz['d']+"/points.xml"])2)非阻塞的时候方式:Ifyouwanttodothingswhileitisexecutingorfeedthingsintostdin,youcanusecommunicateafterthepopencall.#startandprocessthings,thenwaitp=subprocess.Popen(([data["om_points"],">",diz['d']+"/points.xml"])print"Happenswhilerunning"p.communicate()#nowwaitAsstatedinthedocumentation,waitcandeadlock,socommunicateisadvisable.

Unix Popen.communicate无法gzip大文件

我需要在shell命令的基础上使用python gzip大小超过10 GB的文件,因此决定使用子进程Popen。

这是我的代码:

outputdir = '/mnt/json/output/'
inp_cmd='gzip -r ' + outputdir

pipe = Popen(["bash"], stdout =PIPE,stdin=PIPE,stderr=PIPE)
cmd = bytes(inp_cmd.encode('utf8'))
stdout_data,stderr_data = pipe.communicate(input=cmd)

它不是gzip输出目录中的文件。任何出路?

答案

最好的方法是使用subprocess.call()而不是subprocess.communicate()。

call()等到命令完全执行,而在Popen()中,必须外在地使用wait()方法执行才能完成。

另一答案

你试过这样的话:

output_dir = "/mnt/json/output/"

cmd = "gzip -r {}".format(output_dir)

proc = subprocess.Popen(
    cmd,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    stdin=subprocess.PIPE,
    shell=True,
)

out, err = proc.communicate()

以上是关于Python Popen communicate 和wait使用上的区别的主要内容,如果未能解决你的问题,请参考以下文章

如何使用子进程 Popen.communicate() 方法?

Python Popen communicate 和wait使用上的区别

Python Popen communicate 和wait使用上的区别

带有标准输入的 subprocess.Popen.communicate() 的管道损坏

了解 Popen.communicate

当 Popen.communicate() 还不够?