【问题标题】:Async Errors in pythonpython中的异步错误
【发布时间】:2020-07-01 20:32:57
【问题描述】:

我正在编写一个电报用户机器人(带有 Telethon),它每 60 秒向某些聊天发送一条消息。

我正在使用 2 个线程,但出现以下错误:“RuntimeWarning: coroutine 'sender' was never awaited”和“no running event loop”。

我的代码

....

async def sender():
    for chat in chats :
        try:
            if  chat.megagroup == True:
                await client.send_message(chat, messaggio)
        except:
            await client.send_message(myID, 'error')
schedule.every(60).seconds.do(asyncio.create_task(sender()))

...
class checker1(Thread):
    def run(self):
        while True:
            schedule.run_pending()
            time.sleep(1)
class checker2(Thread):
    def run(self):
        while True:
            client.add_event_handler(handler)
            client.run_until_disconnected()
checker2().start()
checker1().start()

我搜索了一个解决方案,但我没有找到任何东西......

【问题讨论】:

  • 确切地说:sender 在哪里等待?

标签: python multithreading python-asyncio schedule telethon


【解决方案1】:

除非您知道自己在做什么,否则您应该避免使用带有asyncio 的线程。可以使用asyncio 重写代码,如下所示,因为大多数时候您实际上并不需要线程:

import asyncio

async def sender():
    for chat in chats :
        try:
            if  chat.megagroup == True:
                await client.send_message(chat, messaggio)
        except:
            await client.send_message(myID, 'error')

async def checker1():
    while True:
        await sender()
        await asyncio.sleep(60)  # every 60s

async def main():
    await asyncio.create_task(checker1())  # background task
    await client.run_until_disconnected() 

client.loop.run_until_complete(main())

这段代码并不完美(您应该在程序结束时正确取消并等待checker1),但它应该可以工作。

附带说明,您不需要client.run_until_disconnected()。调用只是阻塞(运行),直到客户端断开连接。如果你可以让程序以不同的方式运行,只要asyncio 运行,client 就可以工作。

另一件事:裸except: 是一个非常糟糕的主意,并且可能会导致异常问题。至少,将其替换为except Exception

【讨论】:

  • 非常感谢您的帮助!你真的很有帮助
【解决方案2】:

您的代码存在一些问题。 asyncio 抱怨“没有运行事件循环”,因为您的程序永远不会在任何地方启动事件循环,并且在没有运行事件循环的情况下无法安排任务。见Asyncio in corroutine RuntimeError: no running event loop。为了启动事件循环,如果您的程序有一个主协程,您可以使用asyncio.run_until_complete(),或者您可以使用asyncio.get_event_loop().run_forever() 来永久运行事件循环。

第二个问题是schedule.every(60).seconds.do()的错误使用,被第一个错误隐藏了。 schedule 期望传入一个 function,而不是 awaitable(这是 asyncio.create_task(sender()) 返回的)。这通常会导致TypeError,但没有运行事件循环的create_task() 首先引发异常,因此从未引发此异常。您需要定义一个函数,然后将其传递给schedule,如下所示:

def start_sender():
    asyncio.create_task(sender())
schedule.every(60).seconds.do(start_sender)

只要事件循环在程序中的其他地方启动,这应该可以工作。

【讨论】:

  • 我会试试的。感谢您的回复!
  • 我升级了我的代码: def start_sender(): print("done") asyncio.create_task(sender()) schedule.every(60).seconds.do(start_sender) ... asyncio. get_event_loop().run_forever() checker2().start() checker1().start() -> 但现在看起来线程 checker1 不起作用(即使控制台中没有出现错误)
  • @maic0L run_forever() 是一个阻塞调用,这意味着它在完成之前不会退出(通过其他调用stop())。不幸的是,这意味着它之后的任何代码在退出之前都不会运行,这会导致 start() 调用永远不会被执行。尝试将 run_forever() 调用移动到程序的末尾。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-10
相关资源
最近更新 更多