psutil.Process(pid).name 的替代方法

4 投票
2 回答
7559 浏览
提问于 2025-04-16 20:53

我测量了一下 psutil.Process(pid).name 这个功能的性能,发现它的速度比 psutil.Process(pid).exe 慢了十倍以上。因为后者需要不同的权限来访问路径,所以我不能仅仅从路径中提取文件名。我的问题是:有没有其他方法可以替代 psutil.Process(pid).name,实现相同的功能?

2 个回答

3

从psutil 1.1.0版本开始,这个问题已经解决了,详情请查看https://code.google.com/p/psutil/issues/detail?id=426

6

你提到这是在Windows上使用的。我查看了一下psutil在Windows上的工作原理。看起来psutil.Process().name是通过Windows的工具帮助API来获取进程名称的。如果你查看psutil的Process代码并追踪.name,它会调用get_name()这个函数,具体在process_info.c文件里。这个函数会循环遍历你系统上的所有进程ID,直到找到你想要的那个。我觉得这可能是工具帮助API的一个限制。这也是为什么它比.exe慢,因为.exe使用的是不同的API路径,而你提到的那个路径需要额外的权限。

我想到的解决办法是使用ctypes和ctypes.windll直接调用Windows的ntapi。这样只需要PROCESS_QUERY_INFORMATION,这和PROCESS_ALL_ACCESS是不同的:

import ctypes
import os.path

# duplicate the UNICODE_STRING structure from the windows API

class UNICODE_STRING(ctypes.Structure):
    _fields_ = [
      ('Length', ctypes.c_short),
      ('MaximumLength', ctypes.c_short),
      ('Buffer', ctypes.c_wchar_p)
    ]

# args

pid = 8000 # put your pid here

# define some constants; from windows API reference

MAX_TOTAL_PATH_CHARS = 32767
PROCESS_QUERY_INFORMATION = 0x0400 
PROCESS_IMAGE_FILE_NAME = 27

# open handles

ntdll = ctypes.windll.LoadLibrary('ntdll.dll')
process = ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_INFORMATION,
  False, pid)

# allocate memory

buflen = (((MAX_TOTAL_PATH_CHARS + 1) * ctypes.sizeof(ctypes.c_wchar)) +
  ctypes.sizeof(UNICODE_STRING))
buffer = ctypes.c_char_p(' ' * buflen) 

# query process image filename and parse for process "name"

ntdll.NtQueryInformationProcess(process, PROCESS_IMAGE_FILE_NAME, buffer,
  buflen, None)
pustr = ctypes.cast(buffer, ctypes.POINTER(UNICODE_STRING))
print os.path.split(pustr.contents.Buffer)[-1]

# cleanup

ctypes.windll.kernel32.CloseHandle(process)
ctypes.windll.kernel32.FreeLibrary(ntdll._handle)

撰写回答