Python中跨平台获取进程名的PID的方法

60

在主机上有多个同名进程正在运行。如何使用 Python Jython 以跨平台的方式获取这些进程的名称?

  1. 我想要像 pidof 一样的东西,但是使用Python实现。(无论如何我都没有 pidof )。
  2. 我不能解析 / proc ,因为它可能不可用(在HP-UX上)。
  3. 我不想运行 os.popen('ps') 并解析输出,因为我认为它很丑陋(字段序列在不同的操作系统中可能会有所不同)。
  4. 目标平台是 Solaris,HP-UX,和其他可能的平台。
9个回答

83

您可以使用psutil (https://github.com/giampaolo/psutil),它适用于Windows和UNIX:

import psutil

PROCNAME = "python.exe"

for proc in psutil.process_iter():
    if proc.name() == PROCNAME:
        print(proc)
在我的计算机上,它会输出:
<psutil.Process(pid=3881, name='python.exe') at 140192133873040>

编辑于2017年4月27日 - 这是一个更高级的实用函数,它会检查进程的名称是否与name()、cmdline()和exe()匹配:

import os
import psutil

def find_procs_by_name(name):
    "Return a list of processes matching 'name'."
    assert name, name
    ls = []
    for p in psutil.process_iter():
        name_, exe, cmdline = "", "", []
        try:
            name_ = p.name()
            cmdline = p.cmdline()
            exe = p.exe()
        except (psutil.AccessDenied, psutil.ZombieProcess):
            pass
        except psutil.NoSuchProcess:
            continue
        if name == name_ or cmdline[0] == name or os.path.basename(exe) == name:
            ls.append(p)
    return ls

1
不幸的是,即使您只尝试访问由您创建的进程,OS X也不允许您访问许多进程属性(名称、exe、cmdline)。除非您使用sudo运行解释器/脚本。 - John
1
是的,这是OSX的限制(并且它是唯一表现出这种行为的平台)。除了使用sudo/setuid之外,您无法做任何事情。 - Giampaolo Rodolà
1
更新 - 现在已经修复了不同方法的问题,请参见: https://code.google.com/p/psutil/issues/detail?id=297 - Giampaolo Rodolà
那么,如何在多个Python进程中识别我的进程呢? - n611x007
希望能够在Jython中看到psutil的支持。如果psutil不依赖于sys.platform(在我的系统上是'java1.8.0_45')来确定底层操作系统,那么它的一些功能现在可能已经可以使用;需要修复读取/proc的错误;其他使用C扩展API的部分可能会在Stefan的工作完成后实现。 - Jim Baker
显示剩余6条评论

14

没有单一的跨平台API,你需要检查操作系统。对于基于posix的系统,请使用/proc。对于Windows系统,请使用以下代码获取所有pid及其相应的进程名称列表。

from win32com.client import GetObject
WMI = GetObject('winmgmts:')
processes = WMI.InstancesOf('Win32_Process')
process_list = [(p.Properties_("ProcessID").Value, p.Properties_("Name").Value) for p in processes]
你可以轻松地过滤出你需要的进程。 有关 Win32_Process 可用属性的更多信息,请查看 Win32_Process 类

1
这个库在Python中不是标准库,至少在2.7版本中不是。其他版本没有检查过。 - Zoran Pavlovic
2
@ZoranPavlovic 是的,它是带有构建的 pywin32 包 http://sourceforge.net/projects/pywin32/files/pywin32/ 答案应该包括这个。 - n611x007

13
import psutil

process = filter(lambda p: p.name() == "YourProcess.exe", psutil.process_iter())
for i in process:
  print i.name,i.pid

给出所有 "YourProcess.exe" 的 pid。


5
我对此没有任何利益关系;我经常听到人们抱怨说列表推导式总是过滤列表的最佳方式,因为它更快。例如 process = [proc for proc in psutil.process_iter() if proc.name == "YourProcess.exe"] - ThorSummoner

5

有关ThorSummoner的评论的说明

process = [proc for proc in psutil.process_iter() if proc.name == "YourProcess.exe"].

我已经在Debian上使用Python 3尝试过了,我认为应该使用proc.name()而不是proc.name


3

首先,Windows(在所有版本中)是一种非标准操作系统。

Linux(以及大多数专有的Unix系统)是符合POSIX标准的标准操作系统。

C库反映了这种二分法。Python反映了C库。

没有“跨平台”的方法来做到这一点。您必须使用ctypes为特定版本的Windows(XP或Vista)创建一些东西。


1

对于Jython,如果使用Java 5,则可以按以下方式获取Java进程ID:

from java.lang.management import ManagementFactory

pid = int(ManagementFactory.getRuntimeMXBean().getName().split("@")[0])

print(pid)

这段代码将打印出你的进程ID(在我的情况下是 23968


这个可以运行,但是我想获取另一个进程的PID(就像pidof一样,但是不使用pidof)。 - Alex Bolotov

1

我认为你不可能在纯粹基于Python的、可移植的解决方案中找到一个不使用/proc或命令行实用程序的方法,至少在Python本身中是这样。解析os.system并不丑陋——必须有人来处理多个平台,无论是你还是其他人。对于你感兴趣的操作系统来实现它应该相当容易,老实说。


0

只需使用:

def get_process_by_name(name):
    import re, psutil
    ls = list()
    for p in psutil.process_iter():
        if hasattr(p, 'name'):
            if re.match(".*" + name + ".*", p.name()):
                ls.append(p)
    return ls

返回 Process 对象


0

很抱歉,没有这样的方法。进程是通过pid而不是名称唯一标识的。如果您确实必须按名称查找pid,则需要使用类似于您提出的解决方案,但它不具备可移植性,并且可能无法在所有情况下工作。

如果您只需查找某个应用程序的pid,并且您对该应用程序有控制权,则建议将此应用程序更改为将其pid存储在某个位置的文件中,以便您的脚本可以找到它。


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