将 win32com 与多线程一起使用

新手上路,请多包涵

我正在使用 CherryPy 开发一个 Web 应用程序,它需要通过 COM 访问一些应用程序。

现在我为每个请求创建一个新的应用程序实例,这意味着每个请求等待应用程序启动 3 秒,实际作业等待 0.01 秒。

我想启动每个 COM 应用程序一次并使其保持活动状态并在以下请求中重复使用它几秒钟,因为大多数时候它被 5-10 个 ajax 请求突发使用,然后几个小时没有任何请求。

是否可以在 CherryPy 应用程序的所有线程之间共享 COM 对象?

下面是一些实验的总结,展示了它现在如何处理每个请求以及它如何不能跨线程工作。

以下代码成功启动和停止 Excel:

 >>> import pythoncom, win32com.client
>>> def start():
    global xl
    xl = win32com.client.Dispatch('Excel.Application')

>>> def stop():
    global xl
    xl.quit()
    xl = None

>>> start()
>>> stop()

但是下面的代码启动 Excel 并在 3 秒后关闭它。

 >>> import pythoncom, win32com.client, threading, time
>>> def start():
    global xl
    pythoncom.CoInitialize()
    xl = win32com.client.Dispatch('Excel.Application')
    time.sleep(3)

>>> threading.Thread(target=start).start()

我添加了对 CoInitialize() 的调用,否则 xl 对象将不起作用(参见 这篇文章)。

我添加了 3 秒暂停,所以我可以在任务管理器上看到 EXCEL.EXE 进程启动并存活 3 秒。

为什么它在启动它的线程结束后就死了?

我检查了 CoInitialize() 的文档,但我不明白是否有可能让它在多线程环境中工作。

原文由 stenci 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.7k
2 个回答

如果你想在多线程中使用 win32com,你需要做更多的工作,因为 COMObject 不能直接传递给线程。您需要使用 CoMarshalInterThreadInterfaceInStream()CoGetInterfaceAndReleaseStream() 在线程之间传递实例:

 import pythoncom, win32com.client, threading, time

def start():
    # Initialize
    pythoncom.CoInitialize()

    # Get instance
    xl = win32com.client.Dispatch('Excel.Application')

    # Create id
    xl_id = pythoncom.CoMarshalInterThreadInterfaceInStream(pythoncom.IID_IDispatch, xl)

    # Pass the id to the new thread
    thread = threading.Thread(target=run_in_thread, kwargs={'xl_id': xl_id})
    thread.start()

    # Wait for child to finish
    thread.join()

def run_in_thread(xl_id):
    # Initialize
    pythoncom.CoInitialize()

    # Get instance from the id
    xl = win32com.client.Dispatch(
            pythoncom.CoGetInterfaceAndReleaseStream(xl_id, pythoncom.IID_IDispatch)
    )
    time.sleep(5)

if __name__ == '__main__':
    start()

有关详细信息,请参阅: https ://mail.python.org/pipermail/python-win32/2008-June/007788.html

原文由 Mariusz Jamro 发布,翻译遵循 CC BY-SA 4.0 许可协议

@Mauriusz Jamro ( https://stackoverflow.com/a/27966218/7733418 ) 的回答非常有帮助。只是为了添加它,还要确保你这样做:

 pythoncom.CoUninitialize ()

最后这样就没有内存泄漏了。您可以在使用 CoInitialize() 之后和进程结束之前在某处调用它。

原文由 Bipin 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题