Twisted Python IRC机器人-如何异步执行函数以使其不会阻塞机器人?

时间:2019-02-08 13:43:02

标签: python asynchronous twisted irc

我正在尝试编写一个IRC机器人,该机器人在执行较长的功能(10秒钟以上)时仍可继续正常工作。

我首先使用套接字编写机器人。当我调用“阻止”功能(执行该过程需要几秒钟的计算)时,该机器人自然会停止响应,并且在该功能进行计算时不会记录聊天中发送的任何消息。

我做了一次谷歌搜索,看到很多人推荐使用Twisted。

我主要基于一些示例实现了基本的IRC bot:

# twisted imports
from twisted.words.protocols import irc
from twisted.internet import reactor, protocol
from twisted.python import log

# system imports
import time, sys, datetime

def a_long_function():
    time.sleep(180)
    print("finished")

class BotMain(irc.IRCClient):

    nickname = "testIRC_bot"

    def connectionMade(self):
        irc.IRCClient.connectionMade(self)

    def connectionLost(self, reason):
        irc.IRCClient.connectionLost(self, reason)

    # callbacks for events

    def signedOn(self):
        """Signed to server"""
        self.join(self.factory.channel)

    def joined(self, channel):
        """Joined channel"""

    def privmsg(self, user, channel, msg):
        """Received message"""
        user = user.split('!', 1)[0]

        if 'test' in msg.lower():
            print("timeout started")

            a_long_function()

            msg = "test finished"
            self.msg(channel, msg)

        if 'ping' in msg.lower():
            self.msg(channel, "pong")
            print("pong")

class BotMainFactory(protocol.ClientFactory):
    """A factory for BotMains """

    protocol = BotMain

    def __init__(self, channel, filename):
        self.channel = channel
        self.filename = filename

    def clientConnectionLost(self, connector, reason):
        """Try to reconnect on connection lost"""
        connector.connect()

    def clientConnectionFailed(self, connector, reason):
        print ("connection failed:", reason)
        reactor.stop()

if __name__ == '__main__':

    log.startLogging(sys.stdout)
    f = BotMainFactory("#test", "log.txt")
    reactor.connectTCP("irc.freenode.net", 6667, f)
    reactor.run()

这种方法绝对比我以前的套接字实现更好,因为现在该机器人在执行 a_long_function()时仍可以接收发送的消息。

但是,它仅在功能完成后才“看到”这些消息。这意味着当我将消息记录到txt文件时,在 a_long_function()执行时收到的所有消息都收到与函数完成时间相同的时间戳,而不是在聊天室中实际发送的时间戳

此外,该机器人在执行long函数时仍然无法发送任何消息。

有人可以向我指出更改代码的正确方向,以便可以异步执行此长函数,以便机器人在执行过程中仍可以记录并回复消息吗?

谢谢。

编辑: 我遇到了this答案,这使我想到可以在我的 a_long_function 中添加 deferLater 调用,将其拆分为较小的块(即1s执行),然后让漫游器恢复正常运行,以回复并记录同时发送到IRC通道的所有消息。或者,也许添加一个计时器来计算 a_long_function 的运行时间,如果该计时器长于阈值,它将调用 deferLater 来让机器人赶上缓冲的邮件。

这似乎有点骇人听闻-有更好的解决方案吗?

2 个答案:

答案 0 :(得分:0)

不,实际上没有更好的解决方案。除非您要使用线程,否则外观可能会更优雅,但很容易导致程序不稳定。如果可以避免,请采用延迟解决方案。

答案 1 :(得分:0)

要异步调用函数,应将asyncio包与async / await或协程一起使用。请记住,调用async / await是v3的实现,而不是v2。

使用异步/等待:

storage.objects.list

有一个非常不错的教程,您可以阅读here,深入了解asyncio。

希望有帮助!

相关问题