2010-11-12 34 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