在多线程中使用win32com [英] Using win32com with multithreading
问题描述
我正在与CherryPy一起开发一个Web应用程序,该应用程序需要通过COM访问一些应用程序.
I am working on a web app with CherryPy that needs to access a few applications via COM.
现在,我为每个请求创建一个新的应用程序实例,这意味着每个请求等待3秒才能启动应用程序,而实际工作需要等待0.01秒.
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.
我想启动每个COM应用程序一次,并使其保持活动状态,并在以下请求上重用它几秒钟,因为在大多数情况下,它会由5-10个ajax请求突发使用,而在数小时之内就没有使用.
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.
是否可以在CherryPy应用程序的所有线程之间共享COM对象?
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.
以下代码成功启动和停止Excel:
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()
但是以下代码将启动Excel并在3秒后将其关闭.
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()
我将调用添加到CoInitialize()
,否则xl
对象将不起作用(请参阅
I added the call to CoInitialize()
otherwise the xl
object would not work (see this post).
我添加了3秒的暂停时间,因此我可以在任务管理器上看到EXCEL.EXE进程已启动,并且存活了3秒钟.
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?
我检查了 CoInitialize()
,但我不知道是否有可能使其在多线程环境中工作.
I checked the documentation of CoInitialize()
, but I couldn't understand if it is possible to get it to work in multithreaded environment.
推荐答案
如果要在多个线程中使用win32com,则需要做更多的工作,因为COMObject
无法直接传递给线程.您需要使用CoMarshalInterThreadInterfaceInStream()
和CoGetInterfaceAndReleaseStream()
在线程之间传递实例:
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()
有关更多信息,请参见: https://mail.python .org/pipermail/python-win32/2008-June/007788.html
For more info see: https://mail.python.org/pipermail/python-win32/2008-June/007788.html
这篇关于在多线程中使用win32com的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!