2013-08-23 65 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