2014-11-05 65 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