例如,我们有一个耗时任务 task
def task():
while True:
print(f'task is running!')
time.sleep(1)
在主线程,可以根据用户输入,随时中止该任务。
一种容易出错的写法是这样:
import threading
import sys
t1 = threading.Thread(target=task)
t1.start()
while True:
code = input()
if code == 'stop':
sys.exit()
print(code)
当主程序执行到 sys.exit() 时,屏幕上仍然不断打印 task is running!, 只是shell不再接收用户的输入了。这说明,task 线程仍然在运行,阻碍了主程序的退出。
原因是,Python中,非daemon线程并不会随着主线程的退出而退出,daemon 线程则会随着主线程的退出而被杀死。
所以一个简单的改变,让task对应的线程变成deamon线程即可。增加一行代码
t1.daemon = True # 设置线程t1为deamon 线程,则t1会随着 sys.exit() 而死去
不过,这里是强制杀死t1线程,其调用的资源可能不会被正确的释放,因此会导致诡异bug。因此,不推荐这样使用。
更推荐的是使用进程的方式,来管理任务。
import multiprocessing
if __name__ == "__main__":
process = multiprocessing.Process(target=task)
process.daemon = True # 这样主进程退出后,task进程也会退出,跟线程类似 a daemonic process is not allowed to create child processes.
process.start()
while True:
code = input()
if code == 'stop':
process.terminate()
sys.exit()
这是因为,线程之间会共享全局变量,但进程之间是完全隔离的执行环境,所以关闭进程要比关闭线程安全很多。