gpt4 book ai didi

python - 围绕 twisted 的 IRC 客户端编写一个阻塞包装器

转载 作者:太空宇宙 更新时间:2023-11-03 12:42:51 24 4
gpt4 key购买 nike

我正在尝试为 IRC 库编写一个极其简单的界面,如下所示:

import simpleirc

connection = simpleirc.Connect('irc.freenode.net', 6667)
channel = connection.join('foo')
find_command = re.compile(r'google ([a-z]+)').findall

for msg in channel:
for t in find_command(msg):
channel.say("http://google.com/search?q=%s" % t)

their example 开始工作,我遇到麻烦了(代码有点长,所以我粘贴了它 here )。自从调用 channel.__next__回调时需要返回<IRCClient instance>.privmsg被称为,似乎没有一个干净的选择。使用异常或线程在这里似乎是错误的,是否有更简单(阻塞?)的使用扭曲的方式使这成为可能?

最佳答案

通常,如果您尝试以“阻塞”方式使用 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。如果您有一个带有不同 API 的 Googler 版本,这可能会更接近您的要求(上面的那个应该与 Twisted 的 IRCClient 一起工作,因为它是这样写的 -虽然我没有测试它)。 Googler.join 完全有可能返回某种类型的 Channel 对象,并且该 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 即可。当然,yield 表达式仍然存在,我不知道这会让您多么不高兴。 ;)

可以进一步远离回调,并使异步操作所必需的上下文切换完全不可见。这很糟糕,原因与您家外的人行道上散落着看不见的捕熊器也很糟糕。然而,这是可能的。使用类似 corotwine 的东西,本身基于 CPython 的第三方协程库,您可以让 Channel 的实现自己进行上下文切换,而不是要求调用应用程序代码来执行它。结果可能类似于:

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,))

Channel 的实现可能类似于:

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

这又取决于一个新的 Googler 方法,getNextMessage,这是一个基于现有 IRCClient 回调的直接功能添加:

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 函数创建一个新的 greenlet 并切换到它,然后启动 reactor。

from greenlet import greenlet

def main():
greenlet(run).switch()
reactor.run()

run 开始它的第一个异步操作时,它会切换回 reactor greenlet(在本例中是“主要”greenlet,但这并不重要)让异步操作操作完成。当它完成时,corotwine 将回调转换为 greenlet 切换回 run。所以 run 被赋予了直接运行的错觉,就像一个“正常”的同步程序。不过请记住,这只是一种错觉。

因此,您可以随心所欲地远离 Twisted 中最常用的面向回调的样式。不过,这不一定是个好主意。

关于python - 围绕 twisted 的 IRC 客户端编写一个阻塞包装器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2687656/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com