我正在制作的电报机器人可以执行一个需要几分钟才能处理的函数,我希望能够在它处理这个功能时继续使用它。
我正在使用aiogram,异步,我尝试使用Python线程来实现这一点。
我目前的代码是:
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。
发布于 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'])。
https://stackoverflow.com/questions/70907872
复制相似问题