Python中filter对象遍历初始化缓慢问题及进程处理优化咨询
问题分析与优化方案
第一次遍历进程慢的原因
psutil在Windows平台下调用process.open_files()时,首次需要从系统内核枚举进程的所有打开文件句柄,这个操作本身开销较大——尤其是Adobe Acrobat这类可能持有大量资源句柄的进程,第一次调用时没有缓存预热,导致首次迭代耗时久。
针对性优化(解决遍历慢问题)
1. 缩小进程检查范围
不要模糊匹配所有含"Acrobat"的进程,直接精确匹配Acrobat Reader/Pro的进程名:
import psutil def close_acrobat_target_pdf(target_pdf): # 精确匹配进程名,减少需要检查的进程数量 acrobat_process_names = ("AcroRd32.exe", "Acrobat.exe") for proc in psutil.process_iter(["name"]): if proc.info["name"] not in acrobat_process_names: continue try: # 仅对Acrobat进程检查打开文件 for open_file in proc.open_files(): if target_pdf.lower() == open_file.path.lower(): proc.terminate() # 用terminate代替kill,更优雅 proc.wait(timeout=3) return except (psutil.AccessDenied, psutil.NoSuchProcess, psutil.TimeoutExpired): continue
精确匹配进程名可以大幅减少需要检查的进程数量,降低枚举文件句柄的总开销。
2. 先检测文件是否被锁定,再处理进程
避免每次运行都遍历进程,先检查目标PDF是否被占用,仅在被占用时执行进程查找逻辑:
import ctypes from ctypes import wintypes def is_pdf_locked(target_pdf): """检查PDF文件是否被其他进程独占锁定""" GENERIC_READ = 0x80000000 FILE_SHARE_READ = 0x00000001 OPEN_EXISTING = 3 FILE_ATTRIBUTE_NORMAL = 0x00000080 hfile = ctypes.windll.kernel32.CreateFileW( wintypes.LPCWSTR(target_pdf), wintypes.DWORD(GENERIC_READ), wintypes.DWORD(FILE_SHARE_READ), None, wintypes.DWORD(OPEN_EXISTING), wintypes.DWORD(FILE_ATTRIBUTE_NORMAL), None ) if hfile == wintypes.HANDLE(-1).value: ctypes.windll.kernel32.CloseHandle(hfile) return True ctypes.windll.kernel32.CloseHandle(hfile) return False # 调用示例 if is_pdf_locked(target_pdf_path): close_acrobat_target_pdf(target_pdf_path)
这个检测逻辑比遍历进程快得多,只有确认文件被锁定时才会触发Acrobat进程检查。
3. 替代方案:不关闭进程,直接让Acrobat释放文件
如果不想关闭整个Acrobat进程(避免丢失用户其他打开的PDF),可以用pywin32给Acrobat发送关闭指定文档的消息:
import win32gui import win32api import win32con def find_acrobat_windows(): """查找所有Acrobat窗口句柄""" windows = [] def callback(hwnd, extra): window_text = win32gui.GetWindowText(hwnd) if window_text.endswith(".pdf") and "Adobe Acrobat" in window_text: extra.append(hwnd) win32gui.EnumWindows(callback, windows) return windows def close_acrobat_pdf_window(target_pdf): """关闭打开目标PDF的Acrobat窗口""" pdf_name = target_pdf.split("\\")[-1] for hwnd in find_acrobat_windows(): if pdf_name in win32gui.GetWindowText(hwnd): win32api.SendMessage(hwnd, win32con.WM_CLOSE, 0, 0)
这种方式更友好,但需要注意Acrobat的窗口标题格式可能因版本略有不同,需要适配。
整体流程优化建议
替换PDF阅读器为SumatraPDF:这是最彻底的解决方案。SumatraPDF支持TeX编译后的自动刷新,当PDF文件被更新时会自动重新加载,完全不需要处理文件锁定或进程关闭的问题,适配TeX开发场景的体验远优于Acrobat。
增量编译TeX文件:使用
latexmk工具进行增量编译,仅重新编译修改过的部分,减少PDF生成的总耗时,避免不必要的文件覆盖操作。避免重复关闭操作:在脚本中记录上次运行的状态,仅当检测到PDF文件确实被Acrobat占用时才执行关闭逻辑,不要每次运行都执行进程检查。
内容的提问来源于stack exchange,提问作者debsim
相关产品推荐
相关产品推荐

