2013-08-23 64 views
3

當我運行這個時,我得到一個泄漏。我不確定它發生了什麼。我想管不關閉或可能是其他事情發生。感謝一個先進的傢伙!python中運行子進程時泄漏

def deactivateMetadataDevice(input_dmd_lun_wwn): 
    #print('pvremove /dev/mapper/' + input_dmd_lun_wwn) 
    status_cmd = False 
    ps = subprocess.Popen('/sbin/pvremove /dev/mapper/' + input_dmd_lun_wwn, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 
    for line in iter(ps.stdout.readline, ''): 
     print line 
     if re.search('wiped', line): 
      status_cmd = True 
     else: 
      # Cleaning metadata and removing from LVM if ok then return true 
      status_cmd = False 
      raise Warning('\t\t PV /dev/mapper/'+ input_dmd_lun_wwn +' belongs to Volume Group') 

    return status_cmd 

當我運行上面的代碼時出現此問題。

File descriptor 4 (pipe:[323948]) leaked on pvremove invocation. Parent PID 15380: python 
+0

該代碼在沒有「擦除」單詞的第一行中引發異常,然後完全放棄該過程。這是pvremove,所以你應該讓它完成它的工作,繼續閱讀標準輸出,然後做一個ps.wait()。然後你可以提出你的警告。 – tdelaney

回答

3

的問題是,你閱讀完所有的管道中的數據返回之前,你不發出迫不及待地想返回代碼和操作系統的PID表中刪除的過程。我認爲一些調整會做到這一點(我也刪除了一些我認爲是多餘的東西)。

def deactivateMetadataDevice(input_dmd_lun_wwn): 
    #print('pvremove /dev/mapper/' + input_dmd_lun_wwn) 
    status_cmd = False 
    ps = subprocess.Popen('/sbin/pvremove /dev/mapper/' + input_dmd_lun_wwn, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 
    for line in ps.stdout: 
     print line 
     if 'wiped' in line: 
      status_cmd = True 
    ps.wait() 
    # need to handle ps.returncode != 0 
    if status_cmd is False: 
     # Cleaning metadata and removing from LVM if ok then return true 
     raise Warning('\t\t PV /dev/mapper/'+ input_dmd_lun_wwn +' belongs to Volume Group') 
    return status_cmd # likely not needed because you are using exceptions for errors 
+0

另外,由於您不會與子進程進行交互式通信,因此您應該使用'subprocess.check_output' - 它會自動檢查'returncode',收集'stdout'並將其返回,並且當它返回時,您可以確定該過程以某種方式結束 – dnet

+0

@dnet是正確的,有幾種方法來處理它。使用check_output,如果進程返回非零值,則需要處理髮生的錯誤。 Popen.communicate是另一個常年最愛。 – tdelaney

+0

呃......非常感謝你@tdelaney和@dnet !!! – Askar

0

我最終這樣做了。不幸的是,env中的大多數服務器都有python 2.6。 Check_output自帶python 2.7版本。

# check_output in subprocess unfortunately comes by default in 2.7 version 
def check_output(*popenargs, **kwargs): 
    # Passing all arguments to process 
    process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs) 
    output, unused_err = process.communicate() 
    retcode = process.poll() 

    if retcode: 
     cmd = kwargs.get("args") 
     if cmd is None: 
      cmd = popenargs[0] 
     error = subprocess.CalledProcessError(retcode, cmd) 
     error.output = output 
     raise error 

    return output 

# Function to remove metadata from phisical device 
def deactivateMetadataDevice(input_dmd_lun_wwn): 
    #print('pvremove /dev/mapper/' + input_dmd_lun_wwn) 
    status_cmd = False 
    if 'wiped' in check_output(["/sbin/pvremove", "/dev/mapper/" + input_dmd_lun_wwn]): 
     status_cmd = True 

    return status_cmd 
0

我知道這是非常古老的,但我遇到了類似的問題,並認爲我的答案可能會幫助其他人陷入困境,同時尋求幫助。

subprocess.Popen的默認值是close_fds = False(ETA:在Python 3.2中,POSIX的默認值已更改爲True)。但是LVM(8)手冊頁指出:

在調用,LVM要求只有標準文件描述符標準輸入,標準輸出 和stderr可用。如果發現其他人,他們會被關閉,併發出消息 警告泄漏。

因此,對於像pvremove這樣的lvm命令,您可以通過在subprocess.Popen調用中設置close_fds = True來避免泄漏。

+0

@ J.F.Sebastian - 哦,你說得對。我會編輯我的答案,對此更清楚,謝謝。 – NineNineNine