将 win32com 与多线程一起使用 [英] Using win32com with multithreading

查看:59
本文介绍了将 win32com 与多线程一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 CherryPy 开发一个需要通过 COM 访问一些应用程序的网络应用程序.

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

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

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

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

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

<预><代码>>>>导入 pythoncom, win32com.client>>>定义开始():全球 xlxl = win32com.client.Dispatch('Excel.Application')>>>定义停止():全球 xl退出()xl = 无>>>开始()>>>停止()

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

<预><代码>>>>导入 pythoncom、win32com.client、线程、时间>>>定义开始():全球 xlpythoncom.CoInitialize()xl = win32com.client.Dispatch('Excel.Application')时间.sleep(3)>>>threading.Thread(target=start).start()

我添加了对 CoInitialize() 的调用,否则 xl 对象将无法工作(请参阅 这篇文章).

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

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

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

解决方案

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

import pythoncom、win32com.client、线程、时间定义开始():# 初始化pythoncom.CoInitialize()# 获取实例xl = win32com.client.Dispatch('Excel.Application')# 创建idxl_id = pythoncom.CoMarshalInterThreadInterfaceInStream(pythoncom.IID_IDispatch, xl)# 将id传递给新线程thread = threading.Thread(target=run_in_thread, kwargs={'xl_id': xl_id})线程开始()# 等待孩子完成线程连接()def run_in_thread(xl_id):# 初始化pythoncom.CoInitialize()# 从id中获取实例xl = win32com.client.Dispatch(pythoncom.CoGetInterfaceAndReleaseStream(xl_id, pythoncom.IID_IDispatch))时间.sleep(5)如果 __name__ == '__main__':开始()

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

I am working on a web app with CherryPy that needs to access a few applications via COM.

Right now I create a new instance of the application with each request, which means each request waits 3 seconds for the application to start and 0.01 for the actual job.

I would like to start each COM application once and keep it alive and reuse it for a few seconds on the following requests because most of the time it is used by a burst of 5-10 ajax requests, then nothing for hours.

Is it possible to share a COM abject across all the threads of a CherryPy application?

Here is the summary of a few experiments that show how it is working now on each request and how it does not work across threads.

The following code successfully starts and stops 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()

But the following code starts Excel and closes it after 3 seconds.

>>> 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()

I added the call to CoInitialize() otherwise the xl object would not work (see this post).

And I added the 3 second pause, so I could see on the task manager that the EXCEL.EXE process starts and is alive for 3 seconds.

Why does it die after the thread that started it ends?

I checked the documentation of CoInitialize(), but I couldn't understand if it is possible to get it to work in multithreaded environment.

解决方案

If you want to use win32com in multiple threads you need to do a little bit more work as COMObject cannot be passed to a thread directly. You need to use CoMarshalInterThreadInterfaceInStream() and CoGetInterfaceAndReleaseStream() to pass instance between threads:

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()

For more info see: https://mail.python.org/pipermail/python-win32/2008-June/007788.html

这篇关于将 win32com 与多线程一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆