你不能中断你的printfile命令的原因是它包含一个循环遍历整个文件的内容。这意味着privmsg
函数将运行,直到它读取并发送文件中的所有行。只有当它完成后,它才会返回。
Twisted是一个单线程协作式多任务系统。一次只能运行一部分程序。在来自irc服务器的下一行输入可以由irc bot处理之前,privmsg
必须返回。
但是,Twisted还擅长处理事件和管理并发。因此,解决这个问题的一个办法是使用Twisted中包含的一个工具(而不是for循环)发送文件 - 这是一个与系统其余部分协作的工具,同时允许处理其他事件。
下面是一个简单的例子(未经测试,并与一些明显的问题(比如当两个printfile命令到达靠得太近穷人的行为),我不会在这里试着修复):
from twisted.internet.task import cooperate
....
def privmsg(self, user, channel, msg):
nick = user.split('!', 1)[0]
parts = msg.split(' ')
trigger = parts[0]
data = parts[1:]
if trigger == '!printfile':
self._printfile(channel, data[0])
if trigger == '!stop':
self._stopprintfile()
def _printfile(self, channel, name):
myfile = open('/files/%s' % (name,), 'r')
self._printfiletask = cooperate(
self.msg(channel, line.rstrip('\r\n')) for line in myfile)
def _stopprintfile(self):
self._printfiletask.stop()
这使用twisted.internet.task.cooperate
,这是一个接受迭代器(包括生成器)的辅助函数,并以与您的其他应用程序配合的方式运行它们。它通过迭代迭代器几次,然后让其他工作运行,然后返回到迭代器等等,直到迭代器耗尽为止。
这意味着来自irc的新消息即使在文件发送时也会被处理。
但是,还有一点需要考虑的是,irc服务器通常包含防洪保护功能,这意味着可以非常快速地向他们发送很多线路,这可能会让您的机器人断开连接。即使在最好的情况下,irc服务器也可能会缓冲线路,并且只能缓慢释放到网络中。如果机器人已经发送了这些线路,并且他们正坐在irc服务器的缓冲区中,您将无法通过告诉机器人停止(因为它已经完成)而阻止它们出现在网络上。此外,由于这一点,Twisted的irc客户端也具有缓冲功能,所以即使在您拨打self.msg
之后,该线路也可能不会发送实际上,因为irc客户端正在缓冲线路以避免发送它们以至于irc服务器把机器人踢出网络。由于我写的代码只能处理调用到self.msg
,如果它们都已经进入irc客户端的本地缓冲区,您可能仍然不能实际停止发送行。
一个明显的(也许不是理想的)解决所有这些问题是咯,通过插入一个新的延迟有在_printfile
使用的iterator复杂:
from twisted.internet import reactor
from twisted.internet.task import deferLater
def _printfileiterator(self, channel, myfile):
for line in myfile:
self.msg(channel, line)
yield deferLater(reactor, 2, lambda: None)
def _printfile(self, channel, name):
myfile = open('/files/%s' % (name,), 'r')
self._printfiletask = cooperate(self._printfileiterator(channel, myfile))
在这里,我已经改变了迭代器,以便出来的元素是deferLater
(之前,元素全部是None
,因为这是self.msg
的返回值)的延迟。
当cooperate
遇到Deferred
时,它将停止在该迭代器上工作,直到该Deferred
被触发为止。以这种方式使用的deferLater
基本上是合作睡眠功能。它返回一个Deferred
,直到2秒后才会开火(然后它与None
一起触发,其中cooperate
并不特别在意)。在它启动后,cooperate
将继续在迭代器上工作。所以现在_printfile
每两秒钟只发送一行,用stop命令更容易中断。
这是开放式的。我可以告诉你,你不需要线程,但是你真的从中学到了什么实际用途吗?试着问一个更具体的问题。例如,发布一些代码。你试图写IRC机器人在哪里?*不能*接受输入?然后有人可以评论你应该改变什么。见http://sscce.org/ – 2012-08-01 12:03:54
我提出的问题是我有的问题,不管它是否可以回答。 – user1567543 2012-08-02 01:07:38
我的回答有帮助吗? – 2012-11-11 22:27:32