嵌入式环境中的Python子流程块

时间:2019-05-30 14:13:36

标签: python subprocess

我的脚本使用大量文件作为输入,使用subprocess.call()调用外部程序。它可以在常规OS控制台上正常运行,但是在使用嵌入式Python 2.7.x在嵌入式环境中运行时,在处理10个文件左右后挂起。

我提到过各种类似的问题,但找不到适合我的问题:

Python: subprocess.Popen and subprocess.call hang

Python subprocess hangs

Python subprocess call hangs

此深入讨论:https://thraxil.org/users/anders/posts/2008/03/13/Subprocess-Hanging-PIPE-is-your-enemy/

它们都暗指脆弱的缓冲PIPE,并建议对stdoutstderr使用类似文件的对象。因此,我还添加了一个临时文本文件,将其打开,然后将其馈送到stdout的{​​{1}}和stderr中。也不行。

我的旧代码相当简单:

subprocess.call()

主要脚本:

# script1.py

folder = "/path/to/my/folder"
for root, dirs, files in os.walk(folder):
    for file in files:
        path = join(root, file)
        try:
            cmd = ['dir', path, '1>&2']
            _logger.debug(' '.join(cmd))
            completed = subprocess.call(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        except subprocess.CalledProcessError as err:
            _logger.debug(err)
        else:
            _logger.debug('returncode: {}'.format(completed))
print('all done!!')

我已经混合并匹配了几个stdout / stderr解决方案。 包括添加:

try:
    cmd = ['python', 'script1.py', '1>&2']
    ue.log(' '.join(cmd))
    completed = subprocess.call(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as err:
    _logger.error(err)

没有工作。

2 个答案:

答案 0 :(得分:0)

我最终丢弃了所有管道和stdout / stderr,并使用Python 3.7.2的默认subprocess.Popen()参数,即None作为stdout / stderr,并删除了{{1} }。因此,当该程序使用大量输入并可能通过狭窄且隐藏的管道产生巨大的输出波时,基本上就不用理会另一个程序的实时输出。我转向只使用为每个脚本编写的日志文件。

与盲目尝试各种UNIX技巧来解决Windows上的管道问题相比,我对这种解决方案更加满意。

P.S。, 我上面的链接提供了一些答案,建议使用1>&2,我发现令人讨厌的是,嵌入式环境会在每个shell=False中产生大量浮动控制台窗口。

答案 1 :(得分:0)

有一种解决悬管问题的方法,即使用from multiprocessing import Manager 您设置了一个任务队列:

mgr = Manager()

task_queue = mgr.Queue()

将其作为参数传递给进程:

gmat_args.append([gmat_arg, task_queue])
...
pool = Pool(processes=nrunp, maxtasksperchild=20)
...
results = pool.map(run_gmat, gmat_args, chunksize=ninstances)

该过程将写入池:

def run_gmat(args):
    q = args[1]

    scriptname = os.path.basename(args[0])

    proc = sp.Popen(['gmat', '-m', '-ns', '-x', '-r', str(args[0])])

    (outs, errors) = proc.communicate(timeout=cpto)

    outs = outs.decode('UTF-8')

    q.put(filter_outs(outs, scriptname))

然后回到主过程,您读取队列并将其记录:

while 1:

    qout = task_queue.get(cpto)   

    logging.info(qout)

    if task_queue.qsize() < 1:

        break

我不能说这是完美的,我正在运行4000多个作业,并且出现2-3次超时,这似乎与文件I / O有关(该作业在完成时会写入大量报告文件)。为了防止挂起,我捕获到超时异常,将最终的stdout,stderr记录到队列中并终止该作业。我丢失了报告文件,但是从队列中可以看到日志中的超时,因此只需重新运行这2-3个作业即可。