Python后台线程操作COM对象失败:watchdog回调中调用Dispatch无响应如何解决?
问题根因
watchdog的事件回调函数运行在独立的工作线程中,COM组件有严格的线程套间限制,主线程初始化的COM环境无法跨线程共享,之前调用pythoncom.CoInitialize()无效基本是因为初始化位置不对,没有放在回调线程的执行逻辑内。
修复步骤
- 在
on_created回调的最开头初始化当前线程的COM环境,执行结束后对应释放资源 - 不要跨线程传递、使用COM对象,所有Dispatch相关操作必须在创建COM对象的同一个线程内执行
- 可选增加小延迟,避免
on_created触发时新增文件还被写入进程锁定无法操作
修正后代码
事件监听部分
import pythoncom import win32com.client import time class CustomHandler(FileSystemEventHandler): def on_created(self, event): # 为当前回调线程初始化COM环境 pythoncom.CoInitialize() try: print('{} {}'.format(event.src_path, event.event_type)) # 新增1秒延迟,避免文件未写完被锁定 time.sleep(1) get_reports(event.src_path) except Exception as ex: w = ex print(w) write_log(w) finally: # 释放当前线程的COM资源 pythoncom.CoUninitialize() path = config.get("Watcher", "in_dir") event_handler = CustomHandler() observer = PollingObserver() def start_listen(): observer.schedule(event_handler, path, recursive=False) observer.start() try: while observer.isAlive(): observer.join(1) finally: observer.stop() observer.join()
get_reports部分
def get_reports(filter_path): user_name = config.get(branch, "user_name") user_password = config.get(branch, "user_password") server_name = config.get(branch, "server_name") connection_name = config.get(branch, "connection_name") # 在当前线程内创建COM对象,不要复用其他线程创建的COM实例 cc = win32com.client.Dispatch(connection_name) if not cc.IsOpen: try: cc.Open(server_name, user_name, user_password) except Exception as er: write_log(f"连接打开失败:{str(er)}") raise er # 其他业务操作
备选优化方案
如果COM组件仅支持单线程套间,可将所有COM调用逻辑放入固定的单线程队列执行,避免频繁初始化释放COM环境带来的性能损耗。
内容的提问来源于stack exchange,提问作者Qbic
相关产品推荐
相关产品推荐

