【问题标题】:Check if a process is running or not on Windows?检查进程是否在 Windows 上运行?
【发布时间】:2011-12-08 21:12:00
【问题描述】:

我正在尝试创建一个 python 脚本,稍后我将作为服务运行该脚本。现在我只想在 iTunes 运行时运行代码的特定部分。我从一些研究中了解到,轮询整个命令列表然后搜索该列表的应用程序是昂贵的。

我发现基于UNIX的操作系统上的进程会创建一个锁定文件来通知程序当前正在运行,此时我们可以使用os.stat(location_of_file)检查文件是否存在以确定程序是否正在运行或不是。

是否有类似的在 Windows 上创建的锁定文件?

如果不是,Python 中我们可以通过哪些各种方式来确定进程是否正在运行?

我正在使用 python 2.7 和 iTunes COM 接口。

【问题讨论】:

  • 如果 iTunes 没有运行,COM 接口会做什么?
  • 如果在python中使用COM接口创建对象,COM接口会自动打开iTunes。
  • 对于它的价值,它取决于单个程序是否要创建锁定文件或 PID 文件。并非所有 Linux/UNIX 程序都可以。

标签: python windows python-2.7


【解决方案1】:

可以使用下面这个方法检测天气进程 [ 例如:notepad.exe ] 是否正在运行。

from pymem import Pymem
import pymem

while (True):

    try:

        pm = Pymem('notepad.exe')
        print('Notepad Started And Is Running....')

    except:

        print ('Notepad Is Not Running....')

需要 Pymem 包。要安装它,

pip install pymem

【讨论】:

    【解决方案2】:

    您可以只使用os.kill 发送一个 0 信号(不会终止进程)并检查错误。

    from os import kill
    
    def check_if_running(pid):
        try:
            kill(pid, 0)
        except:
            return False
        return True
    

    【讨论】:

      【解决方案3】:

      Psutil 是最好的解决方案。

      import psutil
      
      processes = list(p.name() for p in psutil.process_iter())
      # print(processes)
      count = processes.count("<app_name>.exe")
      
      if count == 1:
          logging.info('Application started')
          # print('Application started')
      else:
          logging.info('Process is already running!')
          # print('Process is already running!')
          sys.exit(0)                          # Stops duplicate instance from running
      

      【讨论】:

        【解决方案4】:

        试试这个代码:

        import subprocess
        def process_exists(process_name):
            progs = str(subprocess.check_output('tasklist'))
            if process_name in progs:
                return True
            else:
                return False
        

        并检查进程是否正在运行:

        if process_exists('example.exe'):
            #do something
        

        【讨论】:

          【解决方案5】:

          有一个名为 wmi 的 python 模块。

          import wmi
          c=wmi.WMI()
          def check_process_running(str_):
              if(c.Win32_Process(name=str_)):
                  print("Process is running")
              else:
                  print("Process is not running")
          
                   
          check_process_running("yourprocess.exe")  
          

          【讨论】:

            【解决方案6】:

            根据每个人的帖子:https://*.com/a/29275361/7530957

            可能会出现多个问题:

            • 多个同名进程
            • 长流程的名称

            如果进程名称很长,'ewerybody's' 代码将不起作用。所以这行有问题:

            last_line.lower().startswith(process_name.lower())
            

            因为 last_line 会比进程名短。

            因此,如果您只想知道一个/多个进程是否处于活动状态:

            from subprocess import check_output
            
            def process_exists(process_name):
                call = 'TASKLIST', '/FI', 'imagename eq %s' % process_name
                if check_output(call).splitlines()[3:]:
                    return True
            

            取而代之的是一个/多个进程的所有信息

            from subprocess import check_output
            
            def process_exists(process_name):
                call = 'TASKLIST', '/FI', 'imagename eq %s' % process_name
                processes = []
                for process in check_output(call).splitlines()[3:]:
                    process = process.decode()
                    processes.append(process.split())
                return processes
            

            【讨论】:

              【解决方案7】:

              虽然@zeller 已经说过这里是一个如何使用tasklist 的例子。因为我只是在寻找 vanilla python 替代品...

              import subprocess
              
              def process_exists(process_name):
                  call = 'TASKLIST', '/FI', 'imagename eq %s' % process_name
                  # use buildin check_output right away
                  output = subprocess.check_output(call).decode()
                  # check in last line for process name
                  last_line = output.strip().split('\r\n')[-1]
                  # because Fail message could be translated
                  return last_line.lower().startswith(process_name.lower())
              

              现在你可以这样做了:

              >>> process_exists('eclipse.exe')
              True
              
              >>> process_exists('AJKGVSJGSCSeclipse.exe')
              False
              

              为避免多次调用并以这种方式对所有流程进行概览,您可以执行以下操作:

              # get info dict about all running processes
              import subprocess
              output = subprocess.check_output(('TASKLIST', '/FO', 'CSV')).decode()
              # get rid of extra " and split into lines
              output = output.replace('"', '').split('\r\n')
              keys = output[0].split(',')
              proc_list = [i.split(',') for i in output[1:] if i]
              # make dict with proc names as keys and dicts with the extra nfo as values
              proc_dict = dict((i[0], dict(zip(keys[1:], i[1:]))) for i in proc_list)
              for name, values in sorted(proc_dict.items(), key=lambda x: x[0].lower()):
                  print('%s: %s' % (name, values))
              

              【讨论】:

              • check_output 是在 python 2.7 中引入的,因此不适用于
              • 这对您来说真的是个问题吗? 2.7 自 2010 年以来就已经发布了 ? 很快就会被弃用 pythonclock.org
              • 仅供参考。是的,就我而言,这是一个问题,因为我们在 python 2.6 中有遗留代码。
              • 要在 Python 3 中工作,请使用 output = subprocess.check_output(call).decode()
              • 谢谢。 @martineau。我修复了两个 sn-ps。现在以相同的方式在 py 2 和 3 中工作?
              【解决方案8】:
              import psutil
              
              def check_process_status(process_name):
                  """
                  Return status of process based on process name.
                  """
                  process_status = [ proc.status() for proc in psutil.process_iter() if proc.name() == process_name ]
                  if process_status:
                      print("Process name %s and staus %s"%(process_name, process_status[0]))
                  else:
                      print("Process name not valid", process_name)
              

              【讨论】:

                【解决方案9】:
                import psutil
                
                for p in psutil.process_iter(attrs=['pid', 'name']):
                    if "itunes.exe" in (p.info['name']).lower():
                        print("yes", (p.info['name']).lower())
                

                适用于 python 3.7


                import psutil
                
                for p in psutil.process_iter(attrs=['pid', 'name']):
                    if p.info['name'] == "itunes.exe":
                        print("yes", (p.info['name']))
                

                这适用于 python 3.8 和 psutil 5.7.0,windows

                【讨论】:

                  【解决方案10】:
                  import subprocess as sp
                  for v in str(sp.check_output('powershell "gps | where {$_.MainWindowTitle}"')).split(' '):
                      if len(v) is not 0 and '-' not in v and '\\r\\' not in v and 'iTunes' in v: print('Found !')
                  

                  【讨论】:

                    【解决方案11】:

                    如果您正在使用 Behave 测试应用程序,您可以使用 pywinauto。 与之前的评论类似,您可以使用此功能:

                    def check_if_app_is_running(context, processName):
                    try:
                        context.controller = pywinauto.Application(backend='uia').connect(best_match = processName, timeout = 5)
                        context.controller.top_window().set_focus()
                        return True
                    except pywinauto.application.ProcessNotFoundError:
                        pass
                    return False
                    

                    backend 可以是“uia”或“win32”

                    timeout 如果在 5 秒内强制重新连接应用程序。

                    【讨论】:

                      【解决方案12】:

                      如果不能像 python 脚本那样依赖进程名称,它将始终以 python.exe 作为进程名称。如果发现这个方法很方便

                      import psutil
                      psutil.pid_exists(pid)
                      

                      查看文档以获取更多信息 http://psutil.readthedocs.io/en/latest/#psutil.pid_exists

                      【讨论】:

                        【解决方案13】:

                        您不能依赖 Linux 或 Windows 中的锁定文件。我会硬着头皮遍历所有正在运行的程序。我真的不相信它会像你想象的那样“昂贵”。 psutil 是一个优秀的跨平台python模块电缆,用于枚举系统上所有正在运行的程序。

                        import psutil    
                        "someProgram" in (p.name() for p in psutil.process_iter())
                        

                        【讨论】:

                        • 在试用这个程序时,即使我以管理员身份运行它,某些进程的访问也会被拒绝。我可能只会使用 try 和 except 来忽略这些实例,但需要注意
                        • 现在好像是BSD
                        • 警告:如果psutil.get_pid_list() 返回的进程在执行psutil.Process(i).name 时已经退出,则会导致psutil.NoSuchProcess 异常。一定要抓住这个。
                        • 当心这种情况。结果区分大小写。
                        • 在我运行的测试中,此方法subprocess 调用tasklist 快10 倍以上(适用于Windows)。
                        【解决方案14】:

                        出于历史目的,我想将此解决方案添加到列表中。它允许您根据 .exe 而不是窗口标题进行查找,还可以返回已使用的内存和 PID。

                        processes = subprocess.Popen('tasklist', stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE).communicate()[0]
                        # Put a regex for exact matches, or a simple 'in' for naive matches
                        

                        一段示例输出:

                        notepad.exe                  13944 Console                    1     11,920 K
                        python.exe                    5240 Console                    1     28,616 K
                        conhost.exe                   9796 Console                    1      7,812 K
                        svchost.exe                   1052 Services                   0     18,524 K
                        iTunes.exe                    1108 Console                    1    157,764 K
                        

                        【讨论】:

                          【解决方案15】:

                          这很好用

                          def running():
                              n=0# number of instances of the program running 
                              prog=[line.split() for line in subprocess.check_output("tasklist").splitlines()]
                              [prog.pop(e) for e in [0,1,2]] #useless 
                              for task in prog:
                                  if task[0]=="itunes.exe":
                                      n=n+1
                              if n>0:
                                  return True
                              else:
                                  return False
                          

                          【讨论】:

                            【解决方案16】:

                            Psutil suggested by Mark,确实是最好的解决方案,唯一的缺点是 GPL 兼容许可证。如果这是一个问题,那么您可以调用 Windows 的进程信息命令:wmic process,其中 WMI 可用(XP pro、vista、win7)或tasklist。这是一个描述:How to call an external program in python and retrieve the output and return code?(不是唯一可能的方式......)

                            【讨论】:

                            • 只是一个警告:tasklist 会截断长名称上的进程名称。例如,它在此处截断 exevmware-usbarbitrator64.ex 2076 Services 0 9,348 K。运行wmic process没有这个问题。
                            【解决方案17】:

                            win32ui.FindWindow(classname, None) 如果找到具有给定类名的任何窗口,则返回窗口句柄。否则它会引发window32ui.error

                            import win32ui
                            
                            def WindowExists(classname):
                                try:
                                    win32ui.FindWindow(classname, None)
                                except win32ui.error:
                                    return False
                                else:
                                    return True
                            
                            if WindowExists("DropboxTrayIcon"):
                                print "Dropbox is running, sir."
                            else:
                                print "Dropbox is running..... not."
                            

                            我发现 Dropbox 托盘图标的窗口类名称是使用 Autohotkey Window Spy 的 DropboxTrayIcon。

                            另见

                            MSDN FindWindow

                            【讨论】:

                            • 谢谢,我真的很喜欢这种方法。我唯一的反对意见是我找不到我的应用程序的类名,即使使用像 AHK Window Spy 这样的程序也是如此。我最终使用了WMICimport subprocess cmd = 'WMIC PROCESS get Caption,Commandline,Processid' proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) for line in proc.stdout: print line
                            • 不用子进程也可以得到 --> procList = wmi.WMI().Win32_Process() print "\n".join (proc.Caption for proc in procList)
                            【解决方案18】:

                            锁定文件通常不会在 Windows 上使用(在 Unix 上很少使用)。通常,当 Windows 程序想要查看其自身的另一个实例是否已在运行时,它会使用已知的标题或类名调用 FindWindow

                            def iTunesRunning():
                                import win32ui
                                # may need FindWindow("iTunes", None) or FindWindow(None, "iTunes")
                                # or something similar
                                if FindWindow("iTunes", "iTunes"):
                                    print "Found an iTunes window"
                                    return True
                            

                            【讨论】:

                            • 这可能适用于 iTunes,但对于可以作为无头实例运行的进程(例如 Excel)呢?这种方法不适用于这些应用程序。
                            • 我认为这个问题非常具体,是关于想要检查 iTunes。
                            • @anijhaw:你是说 Excel 会在没有窗口的情况下运行,还是说FindWindow 不会找到 Excel 的隐藏窗口?
                            • 感谢 win32ui.FindWindow('iTunes,'iTunes') 将完成工作 (Y)
                            • 是的excel可以在没有窗口的情况下运行无头实例
                            【解决方案19】:

                            你对你的 Python 命令运行另一个程序来获取信息感到满意吗?

                            如果是这样,我建议您查看PsList 及其所有选项。例如,以下将告诉您任何正在运行的 iTunes 进程

                            PsList itunes
                            

                            如果你能弄清楚如何解释结果,这应该会让你继续前进。

                            编辑:

                            当我运行 iTunes 时,我得到以下信息:

                            pslist v1.29 - Sysinternals PsList
                            Copyright (C) 2000-2009 Mark Russinovich
                            Sysinternals
                            
                            Process information for CLARESPC:
                            
                            Name                Pid Pri Thd  Hnd   Priv        CPU Time    Elapsed Time
                            iTunesHelper       3784   8  10  229   3164     0:00:00.046     3:41:05.053
                            

                            运行 iTunes 后,我多了一行:

                            iTunes              928   8  24  813 106168     0:00:08.734     0:02:08.672
                            

                            但是,以下命令仅打印出有关 iTunes 程序本身的信息,即使用 -e 参数:

                            pslist -e itunes
                            

                            【讨论】:

                            • 我猜这相当于 - os.popen('query process') 并读取输出行然后搜索 iTuens。因为我真正想要的是使方法更简单。就像在 os.stat(file) 中一样。因为我打算让脚本一直运行。
                            • 好吧,你总是可以定期查询它,例如每秒一次,具体取决于您需要检查的频率。
                            • 我想这是一种可行的解决方案。仍然希望有人能够阐明锁定文件是否是由 Windows 中的程序创建的。谢谢
                            • 好的,我刚刚添加了另一个答案,其中包含可帮助您尝试自行追踪的信息。
                            • 该答案描述了使用 Process Monitor 跟踪 iTunes 在启动时创建的文件,以查看是否创建了任何指标文件。