我正在尝试使用WMI库进行一些非常简单的查询:
到目前为止没问题,直到我开始介绍线程。
我的第一次尝试有一个派生自threading.Thread
的类(规则),并调用另一个执行WMI调用的类(Check)。
为了克服线程问题,我使用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()
这很有效,但在主进程退出时仍然会导致错误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))
线程锁已被创建为类变量,并且为了查询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)
…
非常感谢所有帮助,因为线程和WMI对我来说都是首选。如果我无法使用它,唯一的替代方法是使用WMIC
命令调用替换WMI库,尽管我怀疑这会对性能有所帮助。