2010-11-12 65 views
4

我想要做這樣的事情:背景圖案填充傳入消息隊列並清空傳出消息隊列的扭曲服務器?

twistedServer.start() # This would be a nonblocking call 

while True: 
    while twistedServer.haveMessage(): 
     message = twistedServer.getMessage() 
     response = handleMessage(message) 
     twistedServer.sendResponse(response) 
    doSomeOtherLogic() 

我想這樣做的關鍵是運行在後臺線程服務器。我希望能夠通過線程而不是通過多處理/隊列來實現這一點,因爲我已經爲我的應用程序提供了一層消息傳遞功能,而且我希望避免兩種消息。我提出這個問題是因爲我已經可以在一個單獨的過程中看到如何做到這一點,但是我想知道的是如何在一個線程中完成它,或者如果可以的話。或者,如果可能有其他的模式可以使用,就可以完成同樣的事情,比如編寫我自己的reactor.run方法。謝謝你的幫助。 :)

回答

10

我想要做的關鍵是在後臺線程中運行服務器。

不過,你不能解釋爲什麼這是關鍵。通常,像「使用線程」這樣的東西是實現細節。也許線程也許是合適的,也許不是,但實際目標在這一點上是不可知的。你的目標是什麼?要同時處理多個客戶端?要同時處理來自其他來源(例如Web服務器)的事件的此類消息?在不知道最終目標的情況下,我無法知道我建議的實施策略是否可行。

考慮到這一點,這裏有兩種可能性。

首先,你可能會忘記線程。這將需要定義您的事件處理邏輯如上只有事件處理部分。嘗試獲取事件的部分將被委派給應用程序的另一部分,可能最終基於某個反應器API(例如,您可能會設置一個接受消息的TCP服務器,並將其轉化爲事件,重新處理,在這種情況下,你可以從某種類型的reactor.listenTCP調用開始)。

所以你的例子可能變成像這樣(增加了一些特殊性,試圖增加啓發值):

from twisted.internet import reactor 

class MessageReverser(object): 
    """ 
    Accept messages, reverse them, and send them onwards. 
    """ 
    def __init__(self, server): 
     self.server = server 

    def messageReceived(self, message): 
     """ 
     Callback invoked whenever a message is received. This implementation 
     will reverse and re-send the message. 
     """ 
     self.server.sendMessage(message[::-1]) 
     doSomeOtherLogic() 

def main(): 
    twistedServer = ... 
    twistedServer.start(MessageReverser(twistedServer)) 
    reactor.run() 

main() 

幾點要注意這個例子:

  • 我不知道你的twistedServer是如何定義的。我想象它以某種方式與網絡連接。您的代碼版本會讓它接收消息並緩衝它們,直到它們從您的循環中從緩衝區中移除以進行處理。這個版本可能沒有緩衝區,但只要消息到達,只需調用傳遞給start的對象的messageReceived方法。如果需要,您仍然可以添加某種緩衝,方法是將其放入messageReceived方法中。

  • 現在有一個電話reactor.run將阻止。您可以改爲將此代碼編寫爲twistd插件或.tac文件,在這種情況下,您不會直接負責啓動反應器。但是,有人必須啓動反應堆,否則Twisted的大多數API都不會執行任何操作。 reactor.run塊,當然,直到有人叫reactor.stop

  • 這種方法沒有使用線程。Twisted的協同多任務處理方法意味着你仍然可以同時完成多項任務,只要你注意配合(通常意味着偶爾返回反應堆)。

  • 調用doSomeOtherLogic函數的確切時間會稍微變化,因爲「我剛剛處理了一條消息」之外沒有「緩衝區現在爲空」的概念。你可以改變它,以便每秒調用一次該函數,或者在每N個消息之後或適當的時候。

第二種可能性是真正使用線程。這可能與前面的示例非常相似,但是您可以在另一個線程中調用reactor.run,而不是在主線程中調用reactor.run。例如,

from Queue import Queue 
from threading import Thread 

class MessageQueuer(object): 
    def __init__(self, queue): 
     self.queue = queue 

    def messageReceived(self, message): 
     self.queue.put(message) 

def main(): 
    queue = Queue() 
    twistedServer = ... 
    twistedServer.start(MessageQueuer(queue)) 
    Thread(target=reactor.run, args=(False,)).start() 

    while True: 
     message = queue.get() 
     response = handleMessage(message) 
     reactor.callFromThread(twistedServer.sendResponse, response) 

main() 

此版本假定twistedServer其工作方式相似,但使用一個線程,讓你有while True:循環。注:

  • 如果你使用一個線程,以防止扭曲的嘗試安裝任何信號處理程序,它是由Python只允許安裝在主線程必須調用reactor.run(False)。這意味着Ctrl-C處理將被禁用,並且reactor.spawnProcess將無法​​可靠地工作。

  • MessageQueuerMessageReverser具有相同的接口,只有其執行messageReceived是不同的。它使用線程安全Queue對象在反應器線程(將在其中調用它)和主線程(在while True:循環正在運行)之間進行通信。

  • 您必須使用reactor.callFromThread將消息發送回反應器線程(假設twistedServer.sendResponse實際上基於Twisted API)。扭曲的API通常不是線程安全的,必須在反應器線程中調用。這是reactor.callFromThread爲你做的。

  • 你會想要實現一些方法來停止循環和反應器,一個假設。 python進程不會乾淨地退出,直到調用reactor.stop之後。

注意的是,雖然線程版本給你熟悉的,所需while True循環,它實際上並沒有做任何事情比非線程版本好得多。這只是更復雜。所以,考慮你是否真的需要線程,或者如果他們只是一種可以交換其他東西的實現技術。

+0

首先,感謝您的美妙回答。你是對的,它被穿線並不是關鍵。我想我真正想要的是我的應用程序不被事件驅動。線程示例在這裏看起來很好。我想這是一個荒謬的問題,但是在這個例子之外,你是否給了我一個非事件驅動的扭曲模式?或者,我可能需要另外尋找另一個API?感謝您瞭解您的信息並分享:) – shino 2010-11-12 04:36:48

+0

我之前撰寫過這方面的文章:。你的程序是處理輸入還是輸出?然後它是事件驅動的。非事件驅動的程序只是隨機掛起並且及時停止響應用戶的程序。我還沒有聽到一個很好的理由,爲什麼一個程序應該以非事件驅動的方式編寫 - 也許你可以修復你的問題或問另一個問題,這很清楚爲什麼這對你是可取的? – Glyph 2010-11-12 05:12:37

+0

我可能會那樣做。這是一個可視化客戶端,模擬服務器端。我需要在處理來自客戶端的輸入時不斷更新服務器端的模型。這如何以事件驅動的方式完成? – shino 2010-11-12 05:29:17