如何在Python中知道外部进程是否已经完成?

4

我正在使用 Windows 平台。在我的 Python 脚本中,我可以通过以下方式调用外部程序:

os.system("C:\mainfolder\menu.exe C:\others\file1.inp C:\others\file2.inp")

os.popen("C:\mainfolder\menu.exe C:\others\file1.inp C:\others\file2.inp")

subprocess.call(["C:\mainfolder\menu.exe","C:\others\file1.inp" "C:\others\file2.inp"])

其中:

menu.exe:是我的外部程序。

file1和file2:是我外部程序的输入文件。

以上所有都很好。现在,我外部程序已经成功完成,我需要完全关闭它以及由它打开的所有窗口。我查看了许多其他帖子、Python文档等,并找到了一些命令,例如:

os.system("taskkill /im C:\mainfolder\menu.exe")

os.kill(proc.pid,9)

child.kill() 

但是它们无法正常工作。我花了很多时间尝试找到适合我的解决方案,直到意识到无论我在之后输入哪些命令,它们都不会被读取,因为计算机不知道我的外部程序已经完成。这就是为什么我可以通过在命令行中键入taskkill /im menu.exe随时轻松终止程序,但不能通过Python来实现。

有人知道如何解决这个问题吗?我在调用外部程序时需要包含其他内容吗?


真的吗?我对编程并不是很了解,但我一直认为在编程中一切皆有可能。希望我能找到答案。-( - Sarah
如果您可以修改已打开的程序,在它们关闭之前/之后向您的进程发送信号(例如通过DBus),那么您可以使用IPC来解决这个问题。 - BlackVegetable
1
你不能做任何事情这种说法并不正确,只是在Windows系统中答案可能被深深地隐藏了。在Linux系统中,使用“-9”开关可以终止该进程及其子/父进程,但我不确定taskkill命令的哪个开关相当于此功能。 - Tymoteusz Paul
@Daniel:当menu.exe完成所有处理后,它会留下一个需要手动关闭的活动窗口,一旦我关闭它,Python就会认为menu.exe已经完成。也许在一段时间后杀死程序可以起作用?有更好的解决方法吗? - Sarah
你可以手动控制它,通过任务管理器来检查。这有助于检查os.kill()是否起作用。 - picibucor
显示剩余11条评论
3个回答

2

这里有一些示例代码,用于检测程序是否打开窗口。你只需要知道当menu.exe完成时打开的消息框的标题:

import subprocess
import win32gui
import time


def enumHandler(hwnd, lParam):
    if win32gui.IsWindowVisible(hwnd):
        if 'Menu.exe Finished' in win32gui.GetWindowText(hwnd):
            proc.kill()

proc = subprocess.Popen(["C:\mainfolder\menu.exe","C:\others\file1.inp" "C:\others\file2.inp"])
while proc.poll() is None:
    win32gui.EnumWindows(enumHandler, None)
    time.sleep(1)

当代码检测到有活动窗口时,它会终止我的程序吗? - Sarah
如果有一个特定标题的窗口,终止程序。 - Daniel
这是一个非常有用的代码,我之前不知道它。但在我的情况下,该窗口会在进程的最开始打开。当我的程序正在运行时,它会显示“处理中”,当它完成数据处理时,它会显示“已完成”。窗口的标题保持不变。窗口的标题是我的程序名称。也许有一种方法可以从窗口中提取“已完成”这个词,而不是从标题中提取? - Sarah
@Sarah:这更复杂一些。你需要找到窗口,查找其中所有子元素中带有文本“finished”的标签。这里是一个stackoverflow的答案:https://dev59.com/aG3Xa4cB1Zd3GeqPgpw0 - Daniel
谢谢Daniel,我还在阅读你提供的链接。关于你上面的代码,这是否意味着如果我使用以下方式调用我的程序:proc = subprocess.Popen(["C:\mainfolder\menu.exe","C:\others\file1.inp" "C:\others\file2.inp"]),它会读取以下代码? - Sarah

0

或许我现在才发布我的发现对于这个问题有点晚了,因为我几个月前就问过了,但它仍然可能对其他读者有所帮助。

在那些试图回答我的问题的人们的帮助下,特别是丹尼尔的答案,我找到了解决我的问题的方法。不确定它是否是最好的方法,但我得到了我需要的东西。

基本上,我没有在我的弹出窗口上寻找“完成”这个词,而是寻找我的外部程序生成的结果。如果这些结果已经生成,那么意味着程序已经完成,所以我就杀死了这个进程:

 proc=subprocess.Popen(["C:\mainfolder\menu.exe","C:\others\file1.inp" "C:\others\file2.inp"])
 while proc.poll() is None:
     if os.path.exists("D:\\Results_folder\\Solution.txt"):
           time.sleep(10)
           os.system('taskkill /im menu.exe')

你可以使用 Popen.pid 获取已生成的子进程的进程 ID。然后,你可以在循环中调用 kill -0 PID(如果你正在使用 Windows,请检查 kill 在那里的行为!),直到它的返回值变为 0 或 None - rbaleksandar

0
如果你想要立即结束一个进程,也就是等待它结束,这是一个阻塞调用,os.system()通常会等待,在这里讨论过,以及使用子进程在这里.communicate[0]
如果你想要在程序中稍后结束一个进程,这是一个异步的、非阻塞的过程,可以获取它的pid,根据shell=True与否,它将是生成的shell或子进程的pid。
可以使用该pid来立即通过psutil或os结束它,在这里,或者等待它结束,同时占用很少的CPU时间,但在等待期间可以完成其他任务,或者可以使用线程。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接