我想要做的關鍵是在後臺線程中運行服務器。
不過,你不能解釋爲什麼這是關鍵。通常,像「使用線程」這樣的東西是實現細節。也許線程也許是合適的,也許不是,但實際目標在這一點上是不可知的。你的目標是什麼?要同時處理多個客戶端?要同時處理來自其他來源(例如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
將無法可靠地工作。
MessageQueuer
與MessageReverser
具有相同的接口,只有其執行messageReceived
是不同的。它使用線程安全Queue對象在反應器線程(將在其中調用它)和主線程(在while True:
循環正在運行)之間進行通信。
您必須使用reactor.callFromThread
將消息發送回反應器線程(假設twistedServer.sendResponse
實際上基於Twisted API)。扭曲的API通常不是線程安全的,必須在反應器線程中調用。這是reactor.callFromThread
爲你做的。
你會想要實現一些方法來停止循環和反應器,一個假設。 python進程不會乾淨地退出,直到調用reactor.stop
之後。
注意的是,雖然線程版本給你熟悉的,所需while True
循環,它實際上並沒有做任何事情比非線程版本好得多。這只是更復雜。所以,考慮你是否真的需要線程,或者如果他們只是一種可以交換其他東西的實現技術。
首先,感謝您的美妙回答。你是對的,它被穿線並不是關鍵。我想我真正想要的是我的應用程序不被事件驅動。線程示例在這裏看起來很好。我想這是一個荒謬的問題,但是在這個例子之外,你是否給了我一個非事件驅動的扭曲模式?或者,我可能需要另外尋找另一個API?感謝您瞭解您的信息並分享:) – shino 2010-11-12 04:36:48
我之前撰寫過這方面的文章:。你的程序是處理輸入還是輸出?然後它是事件驅動的。非事件驅動的程序只是隨機掛起並且及時停止響應用戶的程序。我還沒有聽到一個很好的理由,爲什麼一個程序應該以非事件驅動的方式編寫 - 也許你可以修復你的問題或問另一個問題,這很清楚爲什麼這對你是可取的? –
Glyph
2010-11-12 05:12:37
我可能會那樣做。這是一個可視化客戶端,模擬服務器端。我需要在處理來自客戶端的輸入時不斷更新服務器端的模型。這如何以事件驅動的方式完成? – shino 2010-11-12 05:29:17