代码之家  ›  专栏  ›  技术社区  ›  beginner

为什么终止此子流程会引发ProcessLookupError?

  •  4
  • beginner  · 技术社区  · 9 年前

    我无法理解何时需要终止子流程。

    for package in server.packages:
        n = subprocess.Popen(['which', package], stdout=subprocess.DEVNULL)
        n.wait()
        if n.returncode != 0:
            n.kill()
            <some other code>
    

    我收到错误(使用Python3):

    ProcessLookupError: [Errno 3] No such process
    

    有人能解释我子流程何时自杀以及何时需要手动执行吗?

    3 回复  |  直到 9 年前
        1
  •  7
  •   Petri    9 年前

    在Python中, Popen.wait 是等待子进程终止的阻塞调用。因此,在调用 wait 返回。参见Python文档 Popen.wait() .

    现在,如果你理解了它的工作原理,你可以看到你的代码失败了,因为在某个时刻 Popen.returncode 返回一个非零值,然后尝试终止不再存在的进程。

    这就是为什么 ProcessLookupError 升高。

    现在,正如这里的另一个答案所指出的,返回的值可能是 None ,这表示子流程可能存在问题(可能是特定于操作系统的),可以进行检查。Python文档 merely state 那个 没有一个 表示进程仍在运行(负值也是可能的;有关详细信息,请参阅文档)。

    除此之外,如果出于某种原因需要终止仍在运行的子流程,则必须使用以下方法设置并捕获超时:

       try:
          # time out in five seconds
          n.wait(timeout=5)
       except TimeOutExpired:
          # you can use kill, terminate or send_signal method; see the docs
          n.kill()
    

    …或者,不使用 等待 总之:相反,当您在代码中执行其他操作时,让子流程运行,然后稍后再终止它们:

       import os
    
       processes = []
       for package in server.packages:
          n = subprocess.Popen(['which', package], stdout=subprocess.DEVNULL)
          processes.append(n)
    
       <some other code while the subprocesses run (and possibly terminate)>
    
       for p in processes:
          try:
              p.kill()
          except OSError:
              # silently fail if the subprocess has exited already
              pass
    

    如果您只想检查进程是否处于活动状态呢?不幸的是,Python stdlib没有一个好的、方便的方法来检查进程是否正在运行。但是,使用 psutil ,第三方库。有了它,检查流程是否存在就如同:

       pid = n.pid # where n is a subprocess.Popen object from above examples
       import psutil
       psutil.pid_exists(pid) # returns True or False
    
        2
  •  0
  •   Abhi    9 年前

    您可以做的是设置进程的超时,一旦超时,就可以使用以下命令终止进程:

    n.terminate()
    

    您也可以使用

    .is_alive() 
    

    检查进程或线程是否处于活动状态,如果它已经达到超时,则终止它。

        3
  •  0
  •   skyking    9 年前

    您必须检查等待的结果,以确定返回的原因。如果它返回 None 等待返回的原因不是子流程已终止。如果返回的不是 没有一个 这样做是不合适的 kill 但这并不意味着它自动适用于 杀死 如果它回来了 没有一个 .

    例如,根据操作系统 没有一个 可能表示进程的状态更改,您不想为此终止它。但也有可能会出现这种情况 没有一个 ,但仍在运行。您可以在到达 杀死 .

    所以如果你选择 杀死 您可能应该将其包含在 try - catch -语句,以处理子流程已终止的场景。

    也可以从python3.3中添加 timeout (例如 n.wait(timeout=seconds_to_wait) 为了不无限期地等待而等待的参数。

    您的代码可能看起来像:

    for package in server.packages:
        n = subprocess.Popen(['which', package], stdout=subprocess.DEVNULL)
        rc = n.wait() # in python3 you could supply timeout argument
        if rc != None:
            try:
                n.kill()
            except ProcessLookupError:
                pass
            code_to_run_when_killed()
        elif rc != 0:
            code_to_run_when_failed() # or perhaps you should raise exception
        else:
            code_to_run_when_exited_successfully()