Python子进程返回错误的退出代码

时间:2018-02-21 16:21:26

标签: python subprocess exit-code

我编写了一个脚本来启动一系列并行运行的进程(简单单元测试)。它将一次执行//When select is changed update value to array $('select.ticket-qty').on('change', function (e) { //Map the values for the array var arr = $('select.ticket-qty').map(function(){ return this.value }).get() //This sums the all the select options (not what I want) var total = 0; for (var i = 0; i < arr.length; i++) { total += arr[i] << 0; } console.log(total); }); N并行进程的作业。

我的第一个实现分批运行num_workers的进程并且似乎工作正常(我在这里使用num_workers命令来测试行为)

false

然而,测试不会花费相同的时间,所以我有时候等待慢速测试才能完成。因此,我重写了它以便在完成任务时继续分配任务

import subprocess

errors = 0
num_workers = 10
N = 100
i = 0

while i < N:
    processes = []
    for j in range(i, min(i+num_workers, N)):
        p = subprocess.Popen(['false'])
        processes.append(p)

    [p.wait() for p in processes]
    exit_codes = [p.returncode for p in processes]

    errors += sum(int(e != 0) for e in exit_codes)
    i += num_workers

print(f"There were {errors}/{N} errors")

然而,这会在最后几个过程中产生错误的结果。例如,在上面的示例中,它产生98/100错误而不是100.我检查了这与并发性无关;由于某种原因,2个最新的作业返回,退出代码为0。

为什么会这样?

1 个答案:

答案 0 :(得分:1)

问题在于os.wait()。它不仅仅等待子进程退出:它还返回pid和&#34;退出状态指示&#34;那个孩子,the documentation说。这需要等到子进程终止;但是一旦孩子终止了,poll的返回代码就不再可用了。这是一个重现问题的简单测试:

false_runner.py

import os
import subprocess
p = subprocess.Popen(['false'], stderr=subprocess.DEVNULL)
pid, retcode = os.wait()
print("From os.wait: {}".format(retcode))
print("From popen object before poll: {}".format(p.returncode))
p.poll()
print("From popen object after poll: {}".format(p.returncode))

输出

njv@organon:~/tmp$ python false_runner.py
From os.wait: 256
From Popen object before poll: None
From Popen object after poll: 0

The source code for _internal_poll, called by Popen.poll,明确了解此处发生了什么:当Popen尝试在其子流程的pid上调用_waitpid时,它会获得ChildProcessError: [Errno 10] No child processes },并为自己指定一个0 returncode,因为此时无法确定子进程的返回码。

这种情况仅发生在您的示例中的最后几个子进程中的原因是因为os.wait只调用or assigned == N情况,而且只调用一次或两次,因为您的子进程非常快。如果你慢一点,你会得到更多的随机行为。

至于修复:我可能只是在睡眠时替换os.wait()