【问题标题】:Popen does not return in Python 2.7Popen 在 Python 2.7 中不返回
【发布时间】:2016-01-26 12:11:06
【问题描述】:

我正在用 Python 开发一个进程调度程序。这个想法是从主函数创建几个线程,并在每个线程中启动一个外部进程。外部进程应该继续运行,直到它完成或主线程决定停止它(通过发送终止信号),因为超出了进程的 CPU 时间限制。

问题是有时Popen 调用会阻塞并且无法返回。此代码在我的系统(Ubuntu 14.04.3 LTS)上以约 50% 的概率重现该问题:

import os, time, threading, sys
from subprocess import Popen

class Process:
    def __init__(self, args):
        self.args = args

    def run(self):
        print("Run subprocess: " + " ".join(self.args))
        retcode = -1
        try:
                self.process = Popen(self.args)
                print("started a process")
                while self.process.poll() is None:
                    # in the real code, check for the end condition here and send kill signal if required
                    time.sleep(1.0)
                retcode = self.process.returncode
        except:
            print("unexpected error:", sys.exc_info()[0])

        print("process done, returned {}".format(retcode))
        return retcode

def main():
    processes = [Process(["/bin/cat"]) for _ in range(4)]
    # start all processes
    for p in processes:
        t = threading.Thread(target=Process.run, args=(p,))
        t.daemon = True
        t.start()
    print("all threads started")
    # wait for Ctrl+C
    while True:
        time.sleep(1.0)

main()

输出表明只返回了 3 个Popen() 调用:

Run subprocess: /bin/cat
Run subprocess: /bin/cat
Run subprocess: /bin/cat
Run subprocess: /bin/cat
 started a process
started a process
started a process
all threads started

但是,运行ps 表明所有四个进程实际上都已启动!

使用 Python 3.4 时没有出现问题,但我想保持 Python 2.7 的兼容性。

编辑:如果我在启动每个后续线程之前添加一些延迟,问题也会消失。

编辑 2:我做了一些调查,阻塞是由 subprocess.py 模块中的第 1308 行引起的,它试图从父进程中的管道中进行一些读取:

   data = _eintr_retry_call(os.read, errpipe_read, 1048576)

【问题讨论】:

  • 我可以重现您描述的行为。但是,您的示例中存在一些问题:首先,在进入 while 循环之前添加一个输出,并在 Popen() 之后立即添加。这不会改变任何东西,但会使它更清晰一些。然后,可以访问Process.counter,这可能会导致竞争条件,因此请删除它,但这也不会改变问题。然后,肯定有一件事是错误的,那就是finally 子句中的return retcode,因为finally 子句即使在您return 时也会执行,但仍然没有变化。有趣的问题!
  • @UlrichEckhardt 我根据您的建议更新了代码,最后添加了更多信息。

标签: python multithreading python-2.7 process


【解决方案1】:

python 2.7 的 subprocess 模块中存在一些错误,当从多个线程调用 Popen 构造函数时可能会导致死锁。它们在更高版本的 Python 3.2+ IIRC 中得到修复。

您可能会发现使用 Python 3.2/3.3 的 subprocess 模块的 subprocess32 反向端口可以解决您的问题。

*我无法找到实际错误报告的链接,但最近在处理类似问题时遇到了它。

【讨论】:

猜你喜欢
  • 2018-11-14
  • 2014-08-22
  • 2017-08-22
  • 2016-04-18
  • 1970-01-01
  • 2017-10-12
  • 1970-01-01
  • 2016-09-07
  • 2017-01-20
相关资源
最近更新 更多