【问题标题】:Popen process not quitting / releasing when finished in Python在 Python 中完成时,Popen 进程不会退出/释放
【发布时间】:2014-05-21 10:10:39
【问题描述】:

我有一个长时间运行的进程,它在 PC 上运行命令行应用程序。此命令行应用程序处理文件并将日志文件写入它正在读取的目录中。 这段代码是运行应用程序的部分,我一次最多可以运行 4 个线程:

command = "C:\\progra~1\\itms\\iTMSTransporter -m verify -f D:\\TEMP -u username -p password -o D:\\TEMP\\LOGFILE.txt -s provider -v eXtreme"
if slotNumber == 1:
    self.process1 = Popen(command, shell=True, stdin=PIPE)
elif slotNumber == 2:
    self.process2 = Popen(command, shell=True, stdin=PIPE)
elif slotNumber == 3:
    self.process3 = Popen(command, shell=True, stdin=PIPE)
elif slotNumber == 4:
    self.process4 = Popen(command, shell=True, stdin=PIPE)

完成后,它会运行此部分:

if slotNumber == 1:
    wx.CallAfter(self.process1.kill)
elif slotNumber == 2:
    wx.CallAfter(self.process2.kill)
elif slotNumber == 3:
    wx.CallAfter(self.process3.kill)
elif slotNumber == 4:
    wx.CallAfter(self.process4.kill)

唯一的问题是它没有释放目录和日志文件,如果我尝试移动或重命名目录,它说有东西仍在使用它。查看 Windows 任务管理器(下面的屏幕截图),它清楚地显示了很多 cmd.exe 和 conhost.exe。如果我在任务管理器中为所有这些手动“结束进程”,那么目录和日志文件现在被重新释放,我可以删除、移动、重命名等。 如果我在完成目录并立即释放日志文件时从命令窗口通过命令行手动运行此应用程序。 有人知道为什么它们没有在我的 Python 代码中发布吗?

【问题讨论】:

  • 能否提供command的详细信息?
  • 我已更新问题以包含命令。
  • 1) 什么是wx.CallAfter? 2)你说“完成后它会运行这个部分:......”。这句话中的“它”是什么? 3)如果进程已经完成,为什么还要杀死它?是什么让你相信进程完成了它的工作并需要手动杀死?
  • 这是一个线程安全的命令。
  • 使用os.killpg,如[如何终止使用 shell=True 启动的 python 子进程][1] [1] 中所述:*.com/questions/4789837/…

标签: python multithreading popen


【解决方案1】:

考虑使用multiprocessing,并使用myproc.join() 显式等待每个进程完成。示例:

from multiprocessing import Process

def f(name):
    print 'hello', name

if __name__ == '__main__':
    p = Process(target=f, args=('bob',))
    p.start()
    p.join()   # <=== wait for proc to finish

【讨论】:

    【解决方案2】:

    我已经想通了,见下图:

    command = "C:\\progra~1\\itms\\iTMSTransporter.cmd -m verify -f D:\\TEMP -u username -p password -o D:\\TEMP\\LOGFILE.txt -s provider -v eXtreme"
    startupinfo = subprocess.STARTUPINFO()
    startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
    if slotNumber == 1:
        self.process1 = Popen(command, startupinfo=startupinfo, shell=False)
    elif slotNumber == 2:
        self.process2 = Popen(command, startupinfo=startupinfo, shell=False)
    elif slotNumber == 3:
        self.process3 = Popen(command, startupinfo=startupinfo, shell=False)
    elif slotNumber == 4:
        self.process4 = Popen(command, startupinfo=startupinfo, shell=False)
    

    然后退出所有进程:

    if slotNumber == 1:
        Popen("TASKKILL /F /PID {pid} /T".format(pid=self.process1.pid), startupinfo=startupinfo)
    elif slotNumber == 2:
        Popen("TASKKILL /F /PID {pid} /T".format(pid=self.process2.pid), startupinfo=startupinfo)
    elif slotNumber == 3:
        Popen("TASKKILL /F /PID {pid} /T".format(pid=self.process3.pid), startupinfo=startupinfo)
    elif slotNumber == 4:
        Popen("TASKKILL /F /PID {pid} /T".format(pid=self.process4.pid), startupinfo=startupinfo)
    

    现在这会正确退出与每个作业关联的所有进程。

    【讨论】:

      最近更新 更多