无法从 Python 中的线程调用 WMI

ƘɌỈ*_*ƬƠƑ 5 wmi multithreading python-3.x

我正在尝试使用WMI库进行一些非常简单的查询:

  • 服务状态
  • 运行的进程数
  • 可用磁盘空间

到目前为止没问题,直到我开始介绍线程。

我的第一次尝试有一个类(规则)派生自threading.Thread并调用另一个执行 WMI 调用的类(检查)。

为了克服线程问题,我使用该pythoncom库在 WMI 查询的开始和结束时进行初始化和取消初始化。这是它的样子:

class Process(Check):

    def __init__(self, process_name, expected_instances=1):
        self.expected_instances = expected_instances
        self.process_name = process_name


    def run(self):
        import wmi, pythoncom
        pythoncom.CoInitialize()
        try:
            self.wmi_process = wmi.WMI().Win32_Process
            process_count = len(self.wmi_process(name=self.process_name))

            if process_count == self.expected_instances:
                return result.Success('Found {0} {1} processes'.format(process_count, self.process_name))
            else:
                return result.Failure('Found {0} {1} processes, expected {2}'.format(process_count, self.process_name, self.expected_instances))
        finally:
            pythoncom.CoUninitialize()
Run Code Online (Sandbox Code Playgroud)

这有效,但Win32 exception occurred releasing IUnknown在主进程退出时仍会导致错误。

我接受了this SO question中给出的建议,并将WMI查询移动到一个单独的类,该类将有一个实例传递给线程。

class WMIService:

    __lock = threading.Lock()

    def __init__(self):
        log.debug('Initializing WMI')
        pythoncom.CoInitialize()
        self.wmi = wmi.WMI()
        self.wmi_process = self.wmi.Win32_Process
        self.wmi_service = self.wmi.Win32_Service
        self.wmi_disk = self.wmi.Win32_LogicalDisk

    def get_process_count(self, process_name):
        with self.__lock:
            log.debug('Retrieving information for process "{0}"'.format(process_name))
            return len(self.wmi_process(name=process_name))
Run Code Online (Sandbox Code Playgroud)

线程锁已创建为类变量,要查询 WMI,必须先获取锁,排除并行访问(我希望这能解决问题)。

但是,如果我尝试get_process_count()从线程调用该方法,则这是 Python 吐出的错误。同样,在交互式会话中运行它工作得很好。

Traceback (most recent call last):
  File "C:\Users\Admin\pyEnvs\pyWatch\lib\site-packages\wmi.py", line 1001, in _raw_query
    return self._namespace.ExecQuery (strQuery=wql, iFlags=flags)
  File "<COMObject winmgmts:>", line 3, in ExecQuery
  File "C:\Python33\lib\site-packages\win32com\client\dynamic.py", line 282, in _ApplyTypes_
    result = self._oleobj_.InvokeTypes(*(dispid, LCID, wFlags, retType, argTypes) + args)
pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, 'SWbemServicesEx', None, None, 0, -2147221008), None)
…
Run Code Online (Sandbox Code Playgroud)

非常感谢所有帮助,因为线程和 WMI 对我来说都是第一次。如果我不能让它工作,唯一的选择是用WMIC命令调用替换 WMI 库,尽管我怀疑这是否会提高性能。