Более питонный способ выхода из потока Python - демон против stop_event - PullRequest
0 голосов
/ 17 сентября 2018

Следующий код:

import threading
import time
from functools import partial
from itertools import count

def daemon_loop(sleep_interval, stop_event):
    for j in count():
        print(j)
        if stop_event.is_set():
            break
        time.sleep(sleep_interval)
        print('Slept %s' % sleep_interval)
    print('Prod terminating')

if __name__ == '__main__':
    stop_event = threading.Event() #https://stackoverflow.com/a/41139707/281545
    target = partial(daemon_loop, sleep_interval=2, stop_event=stop_event)
    prod_thread = threading.Thread(target=target,
                                   # daemon=True
                                   )

    try:
        prod_thread.start()
        while True:
            time.sleep(10)
    except KeyboardInterrupt:
        print('Terminating...')
        stop_event.set()

печатает на прерывании клавиатуры:

C:\Users\MrD\.PyCharm2018.2\config\scratches>c:\_\Python363-64\python.exe thread_daemon.py
0
Slept 2
1
Terminating...
Slept 2
2
Prod terminating

Раскомментирование строки # daemon=True приводит к немедленному завершению prod_thread:

C:\Users\MrD\.PyCharm2018.2\config\scratches>c:\_\Python363-64\python.exe thread_daemon.py
0
Slept 2
1
Terminating...

Мой вопрос заключается в том, какой предпочтительный / более питонический способ справиться с завершением потока - должен ли я отбросить механизм событий и просто пометить поток как демон, или я пропустил какой-то крайний случай?

См.:

1 Ответ

0 голосов
/ 17 сентября 2018

Я не сделал достаточно Python, чтобы дать вам "Pythonic" ответ, но я могу ответить на более общие термины программирования.

Во-первых, я не фанат завершения потоков.В есть случаи, когда это безопасно и нормально, как, например, ваш пример здесь - но завершение в середине print записи его вывода может показаться немного грязным.

Во-вторых, если выЕсли вы хотите продолжить использовать sleep (я тоже не фанат), вы можете повторить ваши if stop_event.is_set(): и break после сна.(Не перемещайте код, скопируйте его.) Основная проблема с sleep в этом случае состоит в том, что он будет ожидать полного sleep_interval, даже если событие установлено в течение этого времени.

В-третьих -и мое предпочтение - вместо использования sleep сделать wait для события с таймаутом.Если событие не установлено во время ожидания, wait возвращает false после ожидания периода ожидания.Если событие установлено до или во время ожидания , wait возвращает true немедленно (то есть, оно прерывает тайм-аут, давая вам быстрое, чистое отключение потока.)

Итак, ваш код будет выглядеть примерно так:

def daemon_loop(sleep_interval, stop_event):
    for j in count():
        print(j)
        if stop_event.wait(sleep_interval):
            break
        print('Slept %s' % sleep_interval)
    print('Prod terminating')
...