@EugeneVKruglov

Нужно ли (и как) позаботиться о завершении работы нескольких потоков, которые тоже запущены из отдельного потока?

В потоках разбираюсь слабо, поэтому прошу совета.
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)
  • Вопрос задан
  • 72 просмотра
Пригласить эксперта
Ответы на вопрос 1
Vindicar
@Vindicar
RTFM!
Если тебе нужно, чтобы запущенные потоки доработали до конца даже при завершении программы - то можно их просто запустить и оставить.
Сложности обычно начинаются, когда нужно завершить фоновый поток вместе с главным - фоновый поток должен сам проверять, что пора завершаться, и делать это достаточно часто.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы