2011-03-11 80 views
4

我有一種感覺,這其實它不應該那麼困難,但到目前爲止,我還沒有什麼成功。運行鼠兔ioloop背景或使用自定義ioloop

說我有一個名爲PikaClass類包裝pika並提供了一些商業方法。

def PikaClass(object): 
    def __init__(self): 
    # connect to the broker 
    self.connection = pika.SelectConnection(<connection parameters>, self.on_connect) 
    # ..other init stuff.. 

    def on_connect(self, connection): 
    # called when the connection has been established 
    # ..open a channel, declare some queues, etc. 

    def start(self): 
    # start the polling loop 
    self.connection.ioloop.start() 

    def foo(self, **kwargs): 
    # do some business logic, e.g., send messages to particular queues 

直觀地看,這是我想達到的目標:用戶創建的PikaClass實例,設置循環在後臺去,然後通過調用某些業務方法

p = PikaClass() 
p.start() 
bar = p.foo(..) 
與對象進行交互

的問題是,p.start()塊,並防止主代碼從與對象交互一次啓動()被調用。我首先想到的是包裹在一個線程中調用:

Thread(target=p.start()).start() 
bar = p.foo(..) 

但仍然塊,你永遠不會p.foo(..)。文檔中提到你不應該在線程之間共享連接,以便在某個地方引起問題。

我也嘗試使用AsyncoreConnection而不是SelectConnection,並直接調用_connect()(而不是使用ioloop),但沒有任何影響(沒有任何反應)。

那麼,怎樣才能我在後臺運行ioloop,或至少跑我自己ioloop?

注:這是Python的2.6 Win64上(XP)與最新的0.9.4鼠兔

回答

5

的GIL是不是這裏有問題,因爲ioloop花費幾乎所有的時間都處於選擇(2)系統調用,在此期間,GIL被釋放,其他的Python線程可以流掉並執行其他任務。

最簡單的辦法是建立和拆除爲每個請求隊列連接。你可能會認爲這會太昂貴 - 因爲它需要重新驗證,並且(可能)重複每一次連接的SSL協商 - 但它應該是最簡單,最健壯和最容易編寫的,這應該是你的控制因素,除非你知道設置和拆卸實際上會損害整個應用程序的性能(最好通過測試來衡量)。

另一種方法是隻要start()ioloop有一個消息發送,並且接收應答的方法停止ioloop,以便您的程序再次獲得控制權。

connection.ioloop.poller.open = False 

,然後記得要設置回True你再打電話start()之前等待另一個答覆:可以使ioloop回報月初。

-1

您可能需要第二個過程,我不知道很多關於鼠,但如果它是純Python那麼」會希望保持GIL - 記住,你只能在每個進程一次執行一個線程,不管你有多少個核有,由於用於Python的精彩垃圾收集引用計數器的限制。

如果您在if __name__ == "__main__":塊中執行/任何其他操作之前啓動了一個新進程,並將其設置爲等待循環中的事件,則可以向第二個進程發送執行一段工作的指令,然後等待它將結果發回給你。你可能想要實現某種索引系統,這樣你就可以將工作開發到其他進程並忘記它,直到你需要答案。

我唯一的建議,如果你去這個浴缸是爲了避免副作用,或者你將不得不考慮競態條件,僵局,以及GIL保護你的所有其他可怕的東西。在啓動之前向您的進程發送所需的信息,或者確保在它要求您提供該數據之前不要對其進行修改。

這是少數幾個場合之一,Python會把你的槍只給你一個禮貌的筆記,說不要瞄準你的腳。

+0

謝謝,GIL似乎確實是罪魁禍首。但是,我想避免因爲其另一種協議/間接擔心的過程(以及您提到的問題)。另一個解決方法是簡單地在Jython下運行(沒有GIL),並且工作不需要修改我的代碼。所以可能會堅持下去。雖然......知道如何繞過pika的ioloop仍然很好...... – dgorissen 2011-03-11 17:57:53

+0

只要你不太依附任何基於C語言的librabries,jython就會很好。實際上,多線程並不算太糟糕,因爲在jython中線程的使用會遇到同樣的問題,至少你必須明確地共享狀態,以避免一些競爭條件等。 – theheadofabroom 2011-03-12 21:11:40

8

您正在調用'p.start'而不是將其作爲參數傳遞。代碼應該是:

Thread(target=p.start).start() 

線程在執行Thread.start時會調用p.start。

我不確定這是否能解決您的問題,但它可能會幫助您達成解決方案。