Python subprocess.Popen communicate() 和wait()使用上的區別


之所以會糾結到這個問題上是因為發現在調用Popen的wait方法之后程序一直沒有返回。google發現wait是有可能產生死鎖的。為了把這個問題徹底弄清楚,搜索一些資料過來看看:

原文鏈接:http://blog.csdn.net/carolzhang8406/article/details/22286913

看到別人的例子:

今天遇到的一個問題。簡單說就是,使用 subprocess 模塊的 Popen 調用外部程序,如果 stdoutstderr 參數是 pipe,並且程序輸出超過操作系統的 pipe size時,如果使用 Popen.wait() 方式等待程序結束獲取返回值,會導致死鎖,程序卡在 wait() 調用上。

ulimit -a 看到的 pipe size 是 4KB,那只是每頁的大小,查詢得知 linux 默認的 pipe size 是 64KB

看例子:

#!/usr/bin/env python
# coding: utf-8
# yc@2013/04/28

import subprocess

def test(size):
    print 'start'

    cmd = 'dd if=/dev/urandom bs=1 count=%d 2>/dev/null' % size
    p = subprocess.Popen(args=cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)
    #p.communicate()
    p.wait()

    print 'end'

# 64KB
test(64 * 1024)

# 64KB + 1B
test(64 * 1024 + 1)

首先測試輸出為 64KB 大小的情況。使用 dd 產生了正好 64KB 的標准輸出,由 subprocess.Popen 調用,然后使用 wait() 等待 dd 調用結束。可以看到正確的 startend 輸出;然后測試比 64KB 多的情況,這種情況下只輸出了 start,也就是說程序執行卡在了 p.wait() 上,程序死鎖。具體輸出如下:

start
end
start

那死鎖問題如何避免呢?官方文檔里推薦使用 Popen.communicate()。這個方法會把輸出放在內存,而不是管道里,所以這時候上限就和內存大小有關了,一般不會有問題。而且如果要獲得程序返回值,可以在調用 Popen.communicate() 之后取 Popen.returncode 的值。

結論:如果使用 subprocess.Popen,就不使用 Popen.wait(),而使用 Popen.communicate() 來等待外部程序執行結束。

Popen.wait()

Wait for child process to terminate.  Set and returnreturncode attribute.

Warning

This will deadlock when using stdout=PIPE and/orstderr=PIPE and the child process generates enough output to a pipe such that it blocks waiting for the OS pipe buffer to accept more data.  Use communicate() to avoid that.

Popen. communicate ( input=None )

Interact with process: Send data to stdin.  Read data from stdout and stderr, until end-of-file is reached.  Wait for process to terminate. The optionalinput argument should be a string to be sent to the child process, orNone, if no data should be sent to the child.

communicate() returns a tuple (stdoutdata, stderrdata).

Note that if you want to send data to the process’s stdin, you need to create the Popen object with stdin=PIPE.  Similarly, to get anything other thanNone in the result tuple, you need to give stdout=PIPE and/orstderr=PIPE too.

Note

The data read is buffered in memory, so do not use this method if the data size is large or unlimited.

subprocess 的兩種方法:

1)如果想調用之后直接阻塞到子程序調用結束:

Depending on how you want to work your script you have two options. If you want the commands to block and not do anything while it is executing, you can just use subprocess.call.

#start and block until done subprocess.call([data["om_points"], ">", diz['d']+"/points.xml"])


2)非阻塞的時候方式:

If you want to do things while it is executing or feed things into stdin, you can use communicate after the popen call.

#start and process things, then wait p = subprocess.Popen(([data["om_points"], ">", diz['d']+"/points.xml"]) print "Happens while running" p.communicate() #now wait

As stated in the documentation, wait can deadlock, so communicate is advisable.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM