一般来说,如果你试图用“屏蔽”的方式使用twisted,你会遇到很多困难,因为这既不是它的预期用途,也不是大多数人使用它的方式。
遵循流程通常要容易得多,在本例中,这意味着接受回调。问题的回调式解决方案如下:
import re
from twisted.internet import reactor, protocol
from twisted.words.protocols import irc
find_command = re.compile(r'google ([a-z]+)').findall
class Googler(irc.IRCClient):
def privmsg(self, user, channel, message):
for text in find_command(message):
self.say(channel, "http://google.com/search?q=%s" % (text,))
def connect():
cc = protocol.ClientCreator(reactor, Googler)
return cc.connectTCP(host, port)
def run(proto):
proto.join(channel)
def main():
d = connect()
d.addCallback(run)
reactor.run()
这不是绝对必要的(但我强烈建议你考虑试试)。另一种选择是
inlineCallbacks
:
import re
from twisted.internet import reactor, protocol, defer
from twisted.words.protocols import irc
find_command = re.compile(r'google ([a-z]+)').findall
class Googler(irc.IRCClient):
def privmsg(self, user, channel, message):
for text in find_command(message):
self.say(channel, "http://google.com/search?q=%s" % (text,))
@defer.inlineCallbacks
def run():
cc = protocol.ClientCreator(reactor, Googler)
proto = yield cc.connectTCP(host, port)
proto.join(channel)
def main():
run()
reactor.run()
别再注意了
addCallbacks
. 它被替换为
yield
在修饰的生成器函数中。如果你有一个版本的
Googler
使用不同的api
IRCClient
尽管我没有测试它)。完全有可能
Googler.join
归还
Channel
某种东西,为此
通道
对象如下:
@defer.inlineCallbacks
def run():
cc = protocol.ClientCreator(reactor, Googler)
proto = yield cc.connectTCP(host, port)
channel = proto.join(channel)
for msg in channel:
msg = yield msg
for text in find_command(msg):
channel.say("http://google.com/search?q=%s" % (text,))
这只是在现有api的基础上实现这个api的问题。当然了,
产量
表情还在,我不知道这会让你有多难过。;)
可以进一步远离回调,使异步操作所需的上下文开关完全不可见。这是不好的,同样的原因,这将是不好的人行道以外,你的房子被乱扔看不见的捕熊器。不过,这是可能的。使用类似于
corotwine
,本身基于cpython的第三方协同程序库,您可以实现
通道
执行上下文切换本身,而不是要求调用应用程序代码来执行此操作。结果可能类似于:
from corotwine import protocol
def run():
proto = Googler()
transport = protocol.gConnectTCP(host, port)
proto.makeConnection(transport)
channel = proto.join(channel)
for msg in channel:
for text in find_command(msg):
channel.say("http://google.com/search?q=%s" % (text,))
实现了
通道
可能看起来像:
from corotwine import defer
class Channel(object):
def __init__(self, ircClient, name):
self.ircClient = ircClient
self.name = name
def __iter__(self):
while True:
d = self.ircClient.getNextMessage(self.name)
message = defer.blockOn(d)
yield message
这又取决于
古格勒
方法,
getNextMessage
,这是基于现有的
IrCclipse
回调:
from twisted.internet import defer
class Googler(irc.IRCClient):
def connectionMade(self):
irc.IRCClient.connectionMade(self)
self._nextMessages = {}
def getNextMessage(self, channel):
if channel not in self._nextMessages:
self._nextMessages[channel] = defer.DeferredQueue()
return self._nextMessages[channel].get()
def privmsg(self, user, channel, message):
if channel not in self._nextMessages:
self._nextMessages[channel] = defer.DeferredQueue()
self._nextMessages[channel].put(message)
若要运行此命令,请为
run
运行并切换到它,然后启动反应堆。
from greenlet import greenlet
def main():
greenlet(run).switch()
reactor.run()
什么时候?
运行
进入第一个异步操作,它切换回reactor greenlet(在本例中是“主”greenlet,但这并不重要)以完成异步操作。当它完成时,corotwine将回调转换为greenlet开关
运行
. 所以
运行
就像一个“正常”的同步程序,被赋予了直接运行的错觉。不过,请记住,这只是一种幻觉。
因此,可以尽量远离面向回调的样式,这种样式最常用于twisted。不过,这未必是个好主意。