【问题标题】:How to kill a process which is create by popen and uses communicate()?如何杀死由 popen 创建并使用通信()的进程?
【发布时间】:2011-10-23 15:32:51
【问题描述】:

我有一个程序P1,我需要使用不同的输入运行大约 24*20000 次。问题是P1 挂起,我应该手动强制它(kill)。我的第一个解决方案是编写一个 python 脚本来调用P1,并使用popencommunicate 传递正确的输入并接收输出。但是由于等待输出的通信的性质,只要它在等待响应,我就不能杀死进程。我在 Windows 上。

我尝试使用multiprocess 函数,但它只运行P1 并且未能将输入发送给它。我怀疑在popen 中不使用管道并尝试了一点,但我想我无法接收来自P1 的输出。

有什么想法吗?

# This code run XLE and pass the intended input to it automatically
 def startExe(programPath, programArgStr):
 p = subprocess.Popen(programPath,stdout=subprocess.PIPE,stdin=subprocess.PIPE) p.stdin.write(programArgStr)
 p.communicate()[0]
# Need to kill the process if it takes longer than it should here

def main(folder): 
.. 
#loop
programArgStr = "create-parser"+path1+";cd "+ path2+"/s"+ command(counter) +";exit"

startExe(path, programArgStr)
..

您可以看到 P1 是否可以成功完成给定任务,它可以使用传递给它的退出命令自行退出!

【问题讨论】:

    标签: python subprocess kill popen terminate


    【解决方案1】:

    如果您不需要使用 Python,您可以考虑使用 Cygwin Bash 和 timeout(1) 命令来运行带有超时的命令。但是,由于 Cygwin 的 fork() 实现不是很快,并且您正在创建大量进程,因此仅创建进程可能会产生巨大的开销(我不知道 Python 的本机 Windows 版本是否是在这方面更好)。

    或者,如果您有P1 的源代码,为什么不直接修改它,以便它可以在一次调用中执行多次迭代呢?这样一来,您就不必处理创建和杀死 480,000 个进程,如果每次调用所做的工作量很小,这将产生巨大的差异。

    【讨论】:

    • 实际上我无权访问 P1 源代码。我可以执行它。我没有完全明白我可以用 CygWin 做什么。你能解释一下吗?以下是我的一些代码。 # 此代码运行 XLE 并自动将预期的输入传递给它 def startExe(programPath, programArgStr): p = subprocess.Popen(programPath,stdout=subprocess.PIPE,stdin=subprocess.PIPE) p.stdin.write( programArgStr) p.communicate()[0] def main(folder): .. programArgStr = "create-parser"+path1+";cd "+ path2+"/s"+ command(counter) +".txt;+";退出”
    • 我试图编辑我的问题,请问您能再帮我一次吗?
    【解决方案2】:

    当您调用popen 时,您可以指定管道或文件描述符以接受来自进程的标准输出:

    Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None,universal_newlines=False,startupinfo=None,creationflags=0)

    然后您可以监视您传递给 popen 的文件/管道,如果没有写入任何内容,则终止该进程。

    更多关于 popen args 的信息在python docs

    不要使用p.communicate,而是尝试遍历输出行:

    while True:
        line = p.stdout.readline()
        if not line:
            break
        print ">>> " + line.rstrip()
    

    【讨论】:

      【解决方案3】:

      这种方法怎么样?

      from threading import Thread
      def main(input):
          #your actual program, modified to take input as argument
      queue = ['Your inputs stored here. Even better to make it to be a generator']
      class Runner(Thread):
          def __init__(self):
              Thread.__init__(self)
          def run(self):
              while len(queue)>0:
                  input = queue.pop()
                  main(input)
              return True
      #Use 24 threads
      for thread in xrange(24):
          Runner().start()
      #You may also join threads at the end.
      

      当然这种方法会引入一些漏洞,比如“两个线程同时弹出队列列表”,但我在现实生活中从未遇到过。

      【讨论】:

      • 抱歉,我无法访问我的输入程序 :(
      【解决方案4】:

      我通过编辑当前代码并将杀手代码放在单独的文件中解决了我的问题。 为此,我添加了一行来将新创建的进程的 PID 写入文件中。

          #//Should come before p.commiunicate
          WriteStatus(str(p.pid) + "***" + str(gmtime().tm_hour) + "***" + str(gmtime().tm_min))        
          p.communicate()[0]
      

      并且进程监视器单独执行并每 2 分钟检查一次以查看文件中列出的进程是否仍然处于活动状态。如果是,请杀死他们并删除他们的 ID。

       def KillProcess(pid):
      
          subprocess.Popen("TASKKILL /PID "+ str(pid) + " /F /T" , shell=True)
          subprocess.Popen("TASKKILL /im WerFault.exe /F /T" , shell=True)
          print "kill"
      
          def ReadStatus(filePath):
          print "Checking" + filePath
          try:
                  status = open(mainPath+filePath, 'r').readline()
          except:
                  print "file removed" + filePath
                  return 0
          if len(status) >0:
                  info = status.split("***")                
                  time = [gmtime().tm_hour, gmtime().tm_min]
                  print time
      
                  # Time deifferences
                  difHour = time[0]- int(info[1])
                  if difHour == 0: # in the same hour
                          difMin =  time[1]- int(info[2])
                  else:
                          difMin = 60 - int(info[2]) + time[1]
                  if difMin > 2:
                          try:
                                  open(mainPath+filePath, 'w').write("")
                                  KillProcess(info[0])
                          except:
                                  pass
          return 1
      
        def monitor():
          # Read all the files
          listFiles = os.listdir(mainPath)
          while len(listFiles)>0:
                  #GO and check the contents
                  for file in listFiles:
                          #Open the file and Calculate if the process should be killed or not
                          pid = ReadStatus(file)
                          #Update listFiles due to remove of file after finishing the process '
                          # of each folder is done
                          listFiles = os.listdir(mainPath)
                  for i in range(0,4):
                          time.sleep(30) #waits 30 sec
                          subprocess.Popen("TASKKILL /im WerFault.exe /F /T" , shell=True)
          #to indicate the job is done
          return 1
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-28
        • 1970-01-01
        • 2011-06-11
        • 2013-12-18
        • 2022-12-05
        • 1970-01-01
        • 2019-06-20
        • 1970-01-01
        相关资源
        最近更新 更多