2014-11-05 47 views
9

我正在与CherryPy的Web应用程序,需要通过COM访问一些应用程序。使用win32com与多线程

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

我想每次启动每个COM应用程序并保持活动状态,并在以下请求中重复使用它几秒钟,因为大部分时间它被突发的5到10个Ajax请求使用, 。

是否可以在CherryPy应用程序的所有线程中共享COM abject?

下面是几个实验的总结,它们显示了它如何在每个请求上工作,以及它如何在线程间无法工作。

下面的代码成功地启动和停止的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对象将不能正常工作(见this post)。

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

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

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

+1

诀窍可能是初始化多线程单元线程(又称为自由线程)使用。使用'COINIT_APARTMENTTHREADED'选项尝试[CoInitializeEx](http://docs.activestate.com/activepython/2.5/pywin32/pythoncom__CoInitializeEx_meth.html)。 – tdelaney 2014-11-05 19:50:08

回答

7

如果你想在多个线程中使用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

+1

感谢您的代码片段。这非常有用。 – Sanjit 2016-01-20 17:27:50