【问题标题】:Python: Terminate subprocess = Success, but it's still running (?)Python:终止子进程=成功,但它仍在运行(?)
【发布时间】:2015-06-16 11:53:47
【问题描述】:

我有一个简单的脚本,它调用另一个 python 脚本作为子进程。我可以确认子进程已启动并且我可以获取它的 PID。

当我尝试终止子进程(在 win 中)时,我收到正确 PID 的 SUCCESS 消息,但 Windows 任务管理器显示第二个 python.exe 进程仍在运行。

有什么建议可以在 Win 中完成这项任务吗?我将把它扩展到最终也可以在 OSX 和 Linux 中工作:

简化:

#!/usr/bin/env python

import os, sys
import subprocess
from subprocess import Popen, PIPE, STDOUT, check_call

pyTivoPath="c:\pyTivo\pyTivo.py"

print "\nmyPID: %d" % os.getpid()

## Start pyTivo ##
py_process = subprocess.Popen(pyTivoPath, shell=True, stdout=PIPE, stderr=subprocess.STDOUT)
print "newPID: %s" % py_process.pid

## Terminate pyTivo ##  
#py_process.terminate() - for nonWin (?)
py_kill = subprocess.Popen("TASKKILL /PID "+ str(py_process.pid) + " /f") 

raw_input("\nPress Enter to continue...")

注意:需要 Python2.7,psutils 不可用

【问题讨论】:

  • Popen.terminate 有什么问题?文档说它在 Windows 上进行了适当的 win api 调用。
  • 我注意到当我运行 subprocess.Popen 时创建了两个进程。 “cmd.exe”和“python.exe”。我从 py_process.pid 中获取的 PID 指向“cmd.exe”。我只是在我的脚本中终止“cmd.exe”。我不清楚如何获取“python.exe”的 PID。
  • 就是这样:python.exe 是 cmd.exe 的子项。我在我的 TASKKILL 命令中添加了“/T”开关,这也杀死了 python.exe 进程!

标签: python python-2.7


【解决方案1】:

在我的实现中,以下实际上在 Windows 中创建了两个进程(“cmd.exe”和“python.exe”)。

py_process = subprocess.Popen(pyTivoPath, shell=True, stdout=PIPE, stderr=subprocess.STDOUT)

注意到“python.exe”进程是“cmd.exe”进程的子进程,我在我的 TASKKILL 中添加了“/T”(树杀)开关:

py_kill = subprocess.Popen("TASKKILL /PID "+ str(py_process.pid) + " /f /t") 

这会产生有效 KILL python 子进程的预期效果。

【讨论】:

    【解决方案2】:

    创建了两个进程,因为您使用shell=True 调用 Popen。看起来您需要使用 shell 的唯一原因是您使用与解释器的文件关联。要解决您的问题,您还可以尝试:

    from subprocess Popen, PIPE, STDOUT
    
    pyTivoPath = "c:\pyTivo\pyTivo.py"
    cmd = r'c:\Python27\python.exe "{}"'.format(pyTivoPath)
    
    # start process
    py_process = Popen(cmd, stdout=PIPE, stderr=STDOUT)
    
    # kill process
    py_process.terminate()
    

    【讨论】:

      【解决方案3】:

      使用TASKKILL 命令上的/F(强制)开关。许多 Windows 命令没有有用的返回值。不记得TASKKILL 的返回值是否有用。


      抱歉,忽略了您的/F

      你可以尝试直接调用win32 api。

      import win32api
      win32api.TerminateProcess(int(process._handle), -1)
      

      为此找到了ActiveState page。记录了许多 kill 方法,包括上面的 Win32 方法。

      Windows 不允许您终止进程的原因也有很多。常见原因是权限和错误驱动程序具有未正确响应终止信号的未决 I/O 请求。

      有一些程序,例如ProcessHacker,更热衷于杀死进程,但我不确定技术细节,尽管我怀疑强制关闭打开的文件句柄等然后调用 Terminate。

      您在 Linux 上可能会遇到类似的问题,即没有权限终止进程或进程忽略了终止信号。不过在 Linux 上更容易解决,如果 kill -9 不起作用,它就不能被杀死,而且这种情况很少见,因为您必须在代码中显式忽略信号 9。


      0) 你可以使用TASKKILL /T 来杀死 CMD 和 Python 解释器。

      1) 如果您将进程创建更改为直接创建 python 进程(而不是调用 .py 并依赖 cmd 启动),并将脚本名称作为命令参数,您将在创建进程时获得您期望的 PID .

      2) 您可以使用TASKKILL /IM 按名称杀死进程,但名称将是python 解释器,它可能会杀死意外进程。

      【讨论】:

      • 谢谢 Gary,我确实在 TASKKILL 中应用了 /F 开关。没有运气。
      • Gary,添加了 win32api 调用,但看到相同的结果。该过程仍在运行。嗯。
      • 我注意到一件事 - 当我启动子进程时,我看到一个 cmd.exe 进程被启动(以及第二个 python.exe)。杀死 cmd.exe(按名称)返回正确的 PID 和“SUCCESS”,但第二个 python.exe 进程仍在运行。我怀疑我对子流程有一个非常基本的误解。
      • 只是为了笑,你有没有直接从命令行使用 TASKFILL /F ?如果这行得通,我会感到惊讶,如果不行,你有一个 windows 原因导致无法终止进程,即与你的 Python 代码无关。
      • 我认为 taskkill 正在工作,但它正在杀死 cmd.exe 进程,而不是 python.exe 进程(两个进程都是在我 Popen 子进程时创建的)。我找到了一个列出所有打开的进程名称和 PIDS 的 python 脚本——py_process.pid 指向 cmd.exe。
      猜你喜欢
      • 1970-01-01
      • 2011-12-22
      • 2020-12-24
      • 2012-08-20
      • 2013-05-12
      • 1970-01-01
      • 1970-01-01
      • 2013-11-12
      • 2017-08-31
      相关资源
      最近更新 更多