Как сделать чтобы цикл while true не прерывал работу всего бота aiogram
from aiogram import Bot, types
from aiogram.dispatcher import Dispatcher
from aiogram.types import ReplyKeyboardMarkup, KeyboardButton
from aiogram.utils import executor
import parseLevel
import parseAct
import datetime
import asyncio
import threading
BOT_TOKEN = 'TOKEN'
import time
counter_act = 0
counter1 = 0
counter2 = 0
counter3 = 0
counter4 = 0
counter5 = 0
parserLvl = parseLevel.WordsParser()
count_stop = 0
now = datetime.datetime.now()
tim = f'{now.hour}:{now.minute}'
bot = Bot(BOT_TOKEN)
dp = Dispatcher(bot)
CHANGE_KEYBOARD = ReplyKeyboardMarkup(resize_keyboard=True).add(
KeyboardButton("/Змінити рівень або сферу діяльності")
)
LEVEL_KEYBOARD = ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True).add(
KeyboardButton('/level A1'),
KeyboardButton('/level A2'),
KeyboardButton('/level B1'),
KeyboardButton('/level B2'),
KeyboardButton('/level C1/2'),
)
ACTIVITY_KEYBOARD = ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True).add(
KeyboardButton('/Сфера медицини'),
KeyboardButton('/Сфера ІТ'),
KeyboardButton('/Сфера економіки'),
KeyboardButton('/Сфера політики'),
KeyboardButton('/Сфера мистецтво')
)
MAIN_KEYBOARD = ReplyKeyboardMarkup(resize_keyboard=True).add(
KeyboardButton('/0брати за рівнем'),
KeyboardButton('/Обрати за сферою діяльності')
)
@dp.message_handler(commands='start')
async def start_handler(message: types.Message):
global count_stop
await bot.send_message(message.from_user.id,
"Привіт, це бот для вивчення аглійських слів, тут можно обрати свою сферу або свій рівень англійскої мови(А1,В2.....). Обери нижче! \n Після того як оберете тип слів що вам треба вивчати вам буде приходити 5 слів кожний день о 12:00 день.",
reply_markup=MAIN_KEYBOARD)
count_stop+=1
@dp.message_handler(commands='0брати')
async def choose_level_handler(message: types.Message):
await bot.send_message(message.from_user.id, "Оберіть рівень.", reply_markup=LEVEL_KEYBOARD)
@dp.message_handler(commands='Обрати')
async def choose_activity_handler(message: types.Message):
await bot.send_message(message.from_user.id, "Оберіть свою сферу", reply_markup=ACTIVITY_KEYBOARD)
@dp.message_handler(commands='Змінити')
async def stop(message: types.Message):
await bot.send_message(message.from_user.id,
"Привіт, це бот для вивчення аглійських слів, тут можно обрати свою сферу або свій рівень англійскої мови(А1,В2.....). Обери нижче! \n Після того як оберете тип слів що вам треба вивчати вам буде приходити 5 слів кожний день о 12:00 день.",
reply_markup=MAIN_KEYBOARD)
@dp.message_handler(commands='level')
async def level_handler(message: types.Message):
level = message.text.split(' ')[1] # Получаем уровень из текста сообщения
if level == 'A1':
a1_thread = threading.Thread(target=a1(message))
a1_thread.start()
a1_thread.join()
elif level == 'A2':
a2_thread = threading.Thread(target=a2(message))
a2_thread.start()
a2_thread.join()
elif level == 'B1':
b1_thread = threading.Thread(target=b1(message))
b1_thread.start()
b1_thread.join()
elif level == 'B2':
b2_thread = threading.Thread(target=b2(message))
b2_thread.start()
b2_thread.join()
elif level == 'C1/2':
c1_thread = threading.Thread(target=c1(message))
c1_thread.start()
c1_thread.join()
await bot.send_message(message.from_user.id,
f"Ви обрали рівень {level}, тепер вам буде приходить кожен день по 5 слів рівня{level}",
reply_markup=CHANGE_KEYBOARD)
@dp.message_handler(commands='Сфера')
async def act_handler(message: types.Message):
act = message.text.split(' ')[1] # Получаем сферу из текста сообщения
global counter_act
sfera(message, act)
await bot.send_message(message.from_user.id,
f"Ви обрали сферу {act}, тепер вам буде приходить кожен день по 5 слів зі сфери {act}",
reply_markup=CHANGE_KEYBOARD)
def sfera(message : types.Message, act):
global count_stop
global counter1
list = []
if act == 'ІТ':
obj = parseAct.ParseAct()
list = obj.parse_IT()
if act == 'медицини':
obj = parseAct.ParseAct()
list = obj.parse_med()
if act == 'економіки':
obj = parseAct.ParseAct()
list = obj.parse_economic()
if act == 'політики':
obj = parseAct.ParseAct()
list = obj.parse_politice()
if act == 'мистецтво':
obj = parseAct.ParseAct()
list = obj.parse_art()
while True:
now = datetime.datetime.now()
tim = now.strftime('%H:%M')
if tim == '12:00':
if counter1+5 <= len(list):
bot.send_message(message.from_user.id, list[counter1])
bot.send_message(message.from_user.id, list[counter1 + 1])
bot.send_message(message.from_user.id, list[counter1 + 2])
bot.send_message(message.from_user.id, list[counter1 + 3])
bot.send_message(message.from_user.id, list[counter1 + 4])
time.sleep(60)
counter1 += 5
if message.text == '/Змінити рівень або сферу діяльності':
print(1)
break
def a1(message: types.Message):
global count_stop
global counter1
list = parserLvl.parse_words('A1')
while True:
now = datetime.datetime.now()
tim = now.strftime('%H:%M')
print(1)
if tim == '20:59':
bot.send_message(message.from_user.id, list[counter1])
bot.send_message(message.from_user.id, list[counter1 + 1])
bot.send_message(message.from_user.id, list[counter1 + 2])
bot.send_message(message.from_user.id, list[counter1 + 3])
bot.send_message(message.from_user.id, list[counter1 + 4])
time.sleep(60)
counter1 += 5
if message.text == '/Змінити рівень або сферу діяльності':
print(2)
break
def a2(message: types.Message):
global count_stop
global counter2
list = parserLvl.parse_words('A2')
while True:
now = datetime.datetime.now()
tim = now.strftime('%H:%M')
if tim == '12:00':
bot.send_message(message.from_user.id, list[counter2])
bot.send_message(message.from_user.id, list[counter2 + 1])
bot.send_message(message.from_user.id, list[counter2 + 2])
bot.send_message(message.from_user.id, list[counter2 + 3])
bot.send_message(message.from_user.id, list[counter2 + 4])
time.sleep(60)
counter2 += 5
if message.text == '/Змінити рівень або сферу діяльності':
print(1)
break
def b1(message: types.Message):
global count_stop
global counter1
list = parserLvl.parse_words('B1')
while True:
now = datetime.datetime.now()
tim = now.strftime('%H:%M')
if tim == '12:00':
bot.send_message(message.from_user.id, list[counter3])
bot.send_message(message.from_user.id, list[counter3 + 1])
bot.send_message(message.from_user.id, list[counter3 + 2])
bot.send_message(message.from_user.id, list[counter3 + 3])
bot.send_message(message.from_user.id, list[counter3 + 4])
time.sleep(60)
counter1 += 5
if message.text == '/Змінити рівень або сферу діяльності':
print(1)
break
def b2(message: types.Message):
global count_stop
global counter4
list = parserLvl.parse_words('B2')
while True:
now = datetime.datetime.now()
tim = now.strftime('%H:%M')
if tim == '12:00':
bot.send_message(message.from_user.id, list[counter4])
bot.send_message(message.from_user.id, list[counter4 + 1])
bot.send_message(message.from_user.id, list[counter4 + 2])
bot.send_message(message.from_user.id, list[counter4 + 3])
bot.send_message(message.from_user.id, list[counter4 + 4])
time.sleep(60)
counter4 += 5
if message.text == '/Змінити рівень або сферу діяльності':
print(1)
break
def c1(message: types.Message):
global count_stop
global counter5
list = parserLvl.parse_words('C1')
while True:
now = datetime.datetime.now()
tim = now.strftime('%H:%M')
if tim == '12:00':
bot.send_message(message.from_user.id, list[counter5])
bot.send_message(message.from_user.id, list[counter5 + 1])
bot.send_message(message.from_user.id, list[counter5 + 2])
bot.send_message(message.from_user.id, list[counter5 + 3])
bot.send_message(message.from_user.id, list[counter5 + 4])
time.sleep(60)
counter5 += 5
if message.text == '/Змінити рівень або сферу діяльності':
print(1)
break
executor.start_polling(dp, skip_updates=True)
Вот весь код. Помогите решить проблемы. Пытался использовать asyncio и threading. Буду очень рад!
Ответы (4 шт):
Вместо
time.sleep(60)
Напиши
await asyncio.sleep(60)
Также для этого импортитруйте asyncio в начале файла
import asyncio
Ну и нужно чтобы функции в которых ты это используешь также были асинхронными
async def test()
Ваша функция level_handler() создает и запускает новый поток выполнения каждый раз при получении сообщения с командой /level, и в нем вызывается одна из функций a1(), a2(), b1(), b2() или c1(). В каждой из этих функций выполняется бесконечный цикл while True, который никогда не завершается, а значит, и поток выполнения никогда не завершится.
Проблема здесь не в цикле while True, а в том, что вы создаете и запускаете новый поток выполнения каждый раз при получении команды /level, что может привести к накоплению большого количества незавершенных потоков, и ваша программа будет потреблять большое количество ресурсов.
Чтобы избежать этой проблемы, вы можете использовать asyncio и создать асинхронную функцию, которая будет выполняться в бесконечном цикле с помощью asyncio.sleep() и обрабатывать все сообщения, которые приходят от пользователей. Вы можете использовать декоратор @dp.message_handler() для регистрации этой функции как обработчика сообщений.
Вот пример кода, который показывает, как вы можете изменить вашу функцию
level_handler() для использования asyncio
async def level_handler(message: types.Message):
level = message.text.split(' ')[1] # Получаем уровень из текста сообщения
await bot.send_message(message.from_user.id,
f"Ви обрали рівень {level}, тепер вам буде приходить кожен день по 5 слів рівня{level}",
reply_markup=CHANGE_KEYBOARD)
while True:
# Ваш код для обработки сообщений
await asyncio.sleep(1) # Подождать 1 секунду перед следующей итерацией цикла
Замените вызовы a1(), a2(), b1(), b2() и c1() на соответствующий код для обработки сообщений в вашем цикле while True.
На мой взгляд лучшим решением будет открытие while True в новом потоке, вот пример:
from threading import Thread
from time import sleep
def asyncfunciton():
while True:
sleep(100)
th = Thread(target=asyncfunction).start()
#продолжение выполнения другого кода
все что находиться в функции asyncfunction будет выполнено в новом потоке, и никак не будет влиять на основной код
Моя реализация в aiogram3
import asyncio
from aiogram import Bot, Dispatcher
from aiogram.client.bot import DefaultBotProperties
from handlers import user_commands
from config_reader import config
bot = Bot(config.bot_token, default=DefaultBotProperties(parse_mode='HTML'))
dp = Dispatcher()
dp.include_routers(
user_commands.router
)
async def periodic_send():
await bot.send_message(chat_id='XXXXX', text='123')
async def main(bot: Bot):
while True:
try:
updates = await bot.get_updates()
for update in updates:
await dp._process_update(update=update, bot=bot)
await bot.delete_webhook(drop_pending_updates=True)
await periodic_send()
await asyncio.sleep(1)
except Exception as e:
print(f"Ошибка: {e}")
await asyncio.sleep(5)
if __name__ == '__main__':
print('bot starting now')
asyncio.run(main(bot))