В потоках разбираюсь слабо, поэтому прошу совета.
1. При старте бота запускается дополнительный сервисный поток, который предназначен для периодического (1 раз в минуту) запуска неких функций.
2. Эти функции тоже запускаются каждая в своем потоке, а после окончания работы их потоки должны завершиться.
3. При коротком тестировании все вроде бы работает корректно, никакие конфликты не возникают.
Вопрос: действительно ли потоки корректно завершаются и полностью освобождают занятые ресурсы без постороннего вмешательства, или нужно производить дополнительные действия, например, использовать JOIN? В какой момент его использовать, если я не знаю, когда завершаются потоки, а нужно продолжать работу программы? Нужно ли делать так, как в закомментированном куске кода ниже или оставить так, как сделано в другом куске (без использования JOIN)?
Код см. под спойлером, там же уточняющие вопросы и комментарии.
Отрывок рабочего кода
def run_threaded(func):
func_name = 'af_service: ' + func.__name__
def wrapper(*args, **kwargs):
for item in threading.enumerate():
if item.name == func_name:
return None
MyThread = threading.Thread(target = func, name = func_name, args = args, kwargs = kwargs, daemon = True)
MyThread.start()
return MyThread
return wrapper
@run_threaded
def clean_bot_messages(): # Пример функции, запускаемой в отдельном потоке. Декоратор отрабатывает нормально, поток запускается правильно
if not const.get_garbage_cleaning_state():
return
# дальше тело функции, отрабатывает корректно, проблем нет
def thread_jobs(notify: bool):
while const.get_thread_state():
if notify:
print(cur_time(), '- Работает служебный поток...')
print('Число активных потоков:', threading.active_count())
start_time = time.time()
# Закомментированный блок выполняет те же действия, что и блок ниже его:
# нужно ли использовать JOIN или потоки самостоятельно завершатся и освободят ресурсы?
# Вариант 1
#------Работа служебных функций. Они запускаются в отдельных потоках---------
# threads = []
# threads.append(check_schedule())
# threads.append(clean_bot_messages()) # Пример функции, запускаемой в отдельном потоке
# ........ другие функции
# for item in threads:
# item.join()
#------Конец работы служебных функций---------
# Вариант 2
#------Работа служебных функций. Они тоже запускаются в отдельных потоках---------
check_schedule()
clean_bot_messages() # Пример функции, запускаемой в отдельном потоке
# ........ другие функции
#------Конец работы служебных функций---------
time_delta = time.time() - start_time # время, затраченное на работу функций
if notify:
print(cur_time(), f'Служебные функции отработали за {time_delta} сек.')
time.sleep(thread_sleep_time - time_delta)
if notify:
print(cur_time(), '- Служебный поток завершен...')
def start_thread(): # Этот поток запускается при старте бота и работает постоянно, проблем с ним нет
if const.service_thread_is_active():
print('Сервисный поток уже работает...')
else:
print('Сервисный поток еще не активен...')
if const.get_thread_state() and not const.service_thread_is_active():
MyThread = threading.Thread(target = thread_jobs, name='AF_Bot_Service', args = (False,), daemon = True)
MyThread.start()
print('Сервисный поток запущен:', MyThread.name, ', ID:', MyThread.native_id)
if __name__ == '__main__':
start_thread()
bot.infinity_polling(skip_pending = True)