首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python aiogram bot:从另一个线程发送消息

Python aiogram bot:从另一个线程发送消息
EN

Stack Overflow用户
提问于 2022-01-29 17:14:15
回答 1查看 1.4K关注 0票数 0

我正在制作的电报机器人可以执行一个需要几分钟才能处理的函数,我希望能够在它处理这个功能时继续使用它。

我正在使用aiogram,异步,我尝试使用Python线程来实现这一点。

我目前的代码是:

代码语言:javascript
复制
import asyncio
from queue import Queue
from threading import Thread
import time
import logging
from aiogram import Bot, types
from aiogram.types.message import ContentType
from aiogram.contrib.middlewares.logging import LoggingMiddleware
from aiogram.contrib.fsm_storage.memory import MemoryStorage
from aiogram.dispatcher import Dispatcher, FSMContext
from aiogram.utils.executor import start_webhook
from aiogram.types import InputFile

...

loop = asyncio.get_event_loop()
bot = Bot(token=BOT_TOKEN, loop=loop)
dp = Dispatcher(bot, storage=MemoryStorage())
dp.middleware.setup(LoggingMiddleware())

task_queue = Queue()

...

async def send_result(id):
    logging.warning("entered send_result function")
    image_res = InputFile(path_or_bytesio="images/result/res.jpg")
    await bot.send_photo(id, image_res, FINISHED_MESSAGE)


def queue_processing():
    while True:
        if not task_queue.empty():
            task = task_queue.get()
            if task["type"] == "nst":
                nst.run(task["style"], task["content"])
            send_fut = asyncio.run_coroutine_threadsafe(send_result(task['id']), loop)
            send_fut.result()
            task_queue.task_done()
        time.sleep(2)


if __name__ == "__main__":

    executor_images = Thread(target=queue_processing, args=())
    executor_images.start()

    start_webhook(
        dispatcher=dp,
        webhook_path=WEBHOOK_PATH,
        skip_updates=False,
        on_startup=on_startup,
        host=WEBAPP_HOST,
        port=WEBAPP_PORT,
    ) 

因此,我试图设置一个单独的线程,运行一个循环,该循环正在处理一个缓慢任务队列,从而允许在此期间继续与机器人聊天,并在聊天完成任务后向聊天发送结果消息(图像)。

然而,这是行不通的。大约一年前,我的朋友在做类似的任务时想出了这个解决方案,在他的机器人中做工作,但在我的机器人上却不起作用。

从日志判断,它甚至从未进入send_result函数,因为警告永远不会通过。但是,第二个线程确实正常工作,结果映像在nst.run完成工作时保存并位于其指定的路径中。

我尝试了很多不同的东西,我很困惑为什么这个解决方案不适用于我,因为它确实适用于另一个机器人。例如,我尝试使用asyncio.create_task而不是asyncio.run_coroutine_threadsafe,但没有成功。

据我所知,您不再需要将循环传递给aiogram的Bot或Dispatcher,但在这种情况下,我不知道如何将任务从第二个线程发送到主线程。

我正在使用的版本:aigger2.18,异步3.4.3,Python3.9.10。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-02-01 11:42:08

解决的问题是,即使您将自己的异步循环传递给bot或dispatcher,也不能直接访问机器人的循环(使用bot.loop或dp.loop)。

因此,解决方案是使用asyncio.get_event_loop() (如果有)从一个消息处理程序中返回当前正在运行的循环,以访问主线程的循环,因为此时循环正在运行,并将其传递给asyncio.run_coroutine_threadsafe (我使用了“任务”字典),如下所示:asyncio.run_coroutine_threadsafe(send_result(task['id']), task['loop'])

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70907872

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档