如何重置或取消asyncio.sleep事件?

时间:2019-09-14 11:19:05

标签: python-3.x python-asyncio discord.py

我正在尝试建立一个不兼容计时器的机器人。如果有人键入“!challenge”命令,其中一个程序将起作用,在该命令中,机器人将等待60秒以查看是否有人键入“!accept”命令作为响应。如果不是,则说明“挑战已被忽略。重置。”或类似的东西。

另一个计时器实际上是在游戏本身期间运行的,并且长达一个小时。但是,放置命令后,小时会重置。如果游戏空闲一个小时(一个玩家DC或退出),则机器人会重置游戏本身。

我在使用线程:

        # Initiate a challenge to the room. Opponent is whoever uses the !accept command. This command should be
        # unavailable for use the moment someone !accepts, to ensure no one trolls during a fight.
        if message[:10] == "!challenge":
            msg, opponent, pOneInfo, new_game, bTimer, playerOne = message_10_challenge(channel, charFolder, message, unspoiledArena, character,                   self.game)
            if opponent is not "":
                self.opponent = opponent
            if pOneInfo is not None:
                self.pOneInfo = pOneInfo
                self.pOneTotalHP = self.pOneInfo['thp']
                self.pOneCurrentHP = self.pOneInfo['thp']
                self.pOneLevel = self.pOneInfo['level']
            if new_game != 0:
                self.game = new_game
            if bTimer is True:
                timeout = 60
                self.timer = Timer(timeout, self.challengeTimeOut)
                self.timer.start()
            if playerOne is not "":
                self.playerOne = playerOne
            super().MSG(channel, msg)

和:

        # Response to use to accept a challenge.

       if message == "!accept":
            msg, pTwoInfo, new_game, playerTwo, bTimer, bGameTimer, new_oppenent, token = message_accept(channel, charFolder, unspoiledArena,                                character, self.game, self.opponent, self.pOneInfo)
            if not charFile.is_file():
                super().MSG(channel, "You don't even have a character made to fight.")
            else:
                if new_game is not None:
                    self.game = new_game
                if pTwoInfo is not None:
                    self.pTwoInfo = pTwoInfo
                    self.pTwoTotalHP = self.pTwoInfo['thp']
                    self.pTwoCurrentHP = self.pTwoInfo['thp']
                    self.pTwoLevel = self.pTwoInfo['level']
                if bTimer:
                    self.timer.cancel()
                if bGameTimer:
                    gametimeout = 3600
                    self.gameTimer = Timer(gametimeout, self.combatTimeOut)
                    self.gameTimer.start()
                if new_oppenent is not None:
                    self.opponent = new_oppenent
                if playerTwo is not None:
                    self.playerTwo = playerTwo
                if token is not None:
                    self.token = token
                for msg_item in msg:
                    super().MSG(channel, msg_item)

具有功能:

    def challengeTimeOut(self):
        super().MSG(unspoiledArena, "Challenge was not accepted. Challenge reset.")
        self.game = 0

    def combatTimeOut(self):
        super().PRI('Unspoiled Desire', "!reset")

以上是同一游戏的示例,但是在不同的聊天平台上,具有处理计时器的线程。但是我猜线程和discord.py不是朋友。因此,我试图使以上代码与discord.py一起使用,后者似乎使用了asyncio。

想法是在

中使用asyncio.sleep()
if bTimer is true:
     await asyncio.sleep(60)
     self.game = 0
     await ctx.send("Challenge was not accepted. Challenge reset.")

这有效...但是它不会停止计时器,因此即使有人!accepts从而将bTimer更改为False,这也会取消计时器:

if bTimer:
     self.timer.cancel()

它仍然会说“挑战未接受。挑战已重置。”

如果我尝试,bGameTimer也会发生相同的问题:

if bGameTimer:
     await asyncio.sleep(3600)
     await ctx.send("!reset")

1小时后,无论完成与否,游戏都会被硬连线重置。而不是每转一圈都重置1小时计时器,只有在整整一个小时都没有发出命令的情况下才重置。

有没有一种方法可以轻松取消或重置睡眠周期?

1 个答案:

答案 0 :(得分:2)

与您的线程代码等效的异步代码为:

...
    if bTimer:
         self.timer = asyncio.create_task(self.challengeTimeout())
...

async def challengeTimeout(self):
     await asyncio.sleep(60)
     self.game = 0
     await ctx.send("Challenge was not accepted. Challenge reset.")

asyncio.create_task()创建一个轻量级的“任务”对象,该对象大致等同于线程。它与您的其他协程“并行”运行,您可以通过调用其cancel()方法来取消它:

if bTimer:
    self.timer.cancel()