You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的窗口标题格式可能因版本略有不同,需要适配。

整体流程优化建议

  1. 替换PDF阅读器为SumatraPDF:这是最彻底的解决方案。SumatraPDF支持TeX编译后的自动刷新,当PDF文件被更新时会自动重新加载,完全不需要处理文件锁定或进程关闭的问题,适配TeX开发场景的体验远优于Acrobat。

  2. 增量编译TeX文件:使用latexmk工具进行增量编译,仅重新编译修改过的部分,减少PDF生成的总耗时,避免不必要的文件覆盖操作。

  3. 避免重复关闭操作:在脚本中记录上次运行的状态,仅当检测到PDF文件确实被Acrobat占用时才执行关闭逻辑,不要每次运行都执行进程检查。

内容的提问来源于stack exchange,提问作者debsim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 07:07:03