如何防止子进程在python中停止主进程的失败

时间:2014-07-29 19:15:40

标签: python multiprocessing subprocess

我编写了一个python脚本,在一堆多处理文件上运行一个名为“gtdownload”的命令。功能“下载”是我遇到问题的地方。

#/usr/bin/env python

import os, sys, subprocess
from multiprocessing import Pool

def cghub_dnld_file(file1, file2, file3, np):
    <open files>
    <read in lines>
    p = Pool(int(np))
    map_args = [(line.rstrip(),name_lines[i].rstrip(),bar_lines[i].rstrip()) for i, line in enumerate(id_lines)]
    p.map(download_wrapper,map_args)

def download(id, name, bar):
    <check if file has been downloaded, if not download>
    <.....>
    link = "https://cghub.ucsc.edu/cghub/data/analysis/download/" + id
    dnld_cmd = "gtdownload -c ~/.cghub.key --max-children 4 -vv -d " + link + " > gt.out 2>gt.err"
    subprocess.call(dnld_cmd,shell=True)

def download_wrapper(args):
    return download(*args)

def main():
    <read in arguments>
    <...>
    cghub_dnld_file(file1,file2,file3,threads)

if __name__ == "__main__":
   main()

如果数据库中不存在此文件,gtdownload将退出,这也会导致我的python作业死机,并出现以下错误:

Traceback (most recent call last):
  File "/rsrch1/rists/djiao/bin/cghub_dnld.py", line 102, in <module>
    main()
  File "/rsrch1/rists/djiao/bin/cghub_dnld.py", line 98, in main
    cghub_dnld_file(file1,file2,file3,threads)
  File "/rsrch1/rists/djiao/bin/cghub_dnld.py", line 22, in cghub_dnld_file
    p.map(download_wrapper,map_args)
  File "/rsrch1/rists/apps/x86_64-rhel6/anaconda/lib/python2.7/multiprocessing/pool.py", line 250, in map
    return self.map_async(func, iterable, chunksize).get()
  File "/rsrch1/rists/apps/x86_64-rhel6/anaconda/lib/python2.7/multiprocessing/pool.py", line 554, in get
    raise self._value
OSError: [Errno 2] No such file or directory

来自gtdownload的实际错误消息:

Welcome to gtdownload-3.8.5a.
Ready to download
Communicating with GT Executive ...
Headers received from the client:  'HTTP/1.1 100 Continue

HTTP/1.1 404 Not Found
Date: Tue, 29 Jul 2014 18:49:57 GMT
Server: Apache/2.2.15 (Red Hat and CGHub)
Strict-Transport-Security: max-age=31536000
X-Powered-By: PHP/5.3.3
Content-Length: 669
Connection: close
Content-Type: text/xml

'

Error:  You have requested to download a uuid which either does not exist within the system, or has not yet reached the 'live' state.  The requested action will not be performed.  Please double check the supplied uuid or contact thelpdesk for further assistance.

我希望脚本跳过不存在的脚本并在下一个脚本上启动gtdownload。我试图将subprocess.call的stderr输出到管道,看看是否有“error”关键字。但它似乎停在精确的subprocess.call命令。与os.system相同。

我做了一个没有多处理的MCV案例,而且子流程根本没有杀死主进程。看起来像多处理会让事情变得混乱,尽管我只使用1个线程进行测试。

#!/usr/bin/env python
import subprocess
#THis is the id that gtdownload had problem with
id = "df1e073f-4485-4d5f-8659-cd8eaac17329"
link = "https://cghub.ucsc.edu/cghub/data/analysis/download/" + id
dlnd_cmd = "gtdownload -c ~/.cghub.key --max-children 4 -vv -d " + link + " > gt.out 2>gt.err"
print dlnd_cmd
subprocess.call(dlnd_cmd,shell=True)
print "done"

显然多处理冲突subprocess.call但我不清楚为什么。

3 个答案:

答案 0 :(得分:1)

  

避免子进程杀死主进程失败的最佳方法是什么?

以某种适当的方式处理异常并继续前进。

try:
    subprocess.call(dlnd_cmd)
except OSError as e:
    print 'failed to download: {!r}'.format(e)

但是,这可能不合适。 subprocess.call引发的异常类型通常不是您可以记录和解决的瞬态事物;如果它现在不能正常工作,那么在你修复底层问题(脚本中的一个错误,或者gtdownload没有正确安装,或者其他什么)之前,它将继续无法工作。

例如,如果您向我们展示的代码是您的实际代码:

dlnd_cmd = "gtdownload -c ~/.cghub.key --max-children 4 -vv -d " + link + " > gt.out 2>gt.err"
subprocess.call(dlnd_cmd)

...然后由于dano的回答中解释的原因,保证会引发OSErrorcall(没有shell=True)将尝试获取整个字符串空间,shell重定向等等 - 作为要在$PATH上查找的可执行程序的名称。而且没有这样的计划。所以它会引发OSError(errno.ENOENT)。 (这正是你所看到的。)只记录对你没有任何好处;整个过程退出是一件好事,因此您可以调试该问题。

答案 1 :(得分:0)

subprocess.call不应该杀死主要进程。您的脚本还有其他一些问题,或者您对脚本行为的结论是错误的。您是否尝试在子进程调用后打印一些跟踪输出?

答案 2 :(得分:0)

您必须使用shell=Truesubprocess.call与参数的字符串一起使用(并使用shell重定向):

subprocess.call(dlnd_cmd, shell=True)

如果没有shell=Truesubprocess会尝试将整个命令字符串视为单个可执行文件名,这当然不存在,并导致No such file or directory例外。< / p>

有关何时使用字符串与何时使用subprocess的序列的详细信息,请参阅this answer