退出python线程的更多pythonic方法-守护程序vs stop_event

时间:2018-09-17 09:59:13

标签: python python-3.x python-multithreading

以下代码:

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...

我的问题是处理线程终止的首选/更多pythonic方法是什么?我应该放弃事件机制,仅将线程标记为守护程序,还是错过一些边缘情况?

请参阅:

1 个答案:

答案 0 :(得分:3)

我做的Python还不够,无法给您“ Pythonic”的答案,但是我可以用更通用的编程术语来回答。

首先,我不喜欢终止线程。在某些情况下,它是安全无事的,例如您在这里的示例,但是在java.io.IOException: com.sun.enterprise.admin.remote.RemoteFailureException: Error occurred during deployment: Exception while loading the app : java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: org.apache.catalina.LifecycleException: java.lang.ClassNotFoundException: devicemanager.models.Action 的中间终止写其输出会感到有点脏。

第二,如果您想继续使用print(我也不喜欢),可以在之后重复sleepif stop_event.is_set(): 睡觉。 (不要移动代码,将其复制。)在这种情况下,break的主要问题在于,即使在该时间段内设置了事件,它也会等待完整的sleep

第三次,也是我的喜好,而不是使用sleep_interval,而是在事件超时的情况下执行sleep。如果在等待期间未设置事件,则wait在等待超时时间后返回false。如果事件是在等待之前或等待期间设置的,则wait立即返回真(emem)(也就是说,它会终止超时,从而为您提供快速,干净的关机时间)线程。)

因此您的代码应如下所示:

wait