sys.exit对多线程的影响是什么?

18
我对Python中的sys.exit()感到非常困惑。 在Python文档中,它说“退出Python”; 这是否意味着当在Python程序中调用sys.exit()时,进程将退出? 如果是这样,下面的代码显示了不同的结果:
import sys
import time
import threading

def threadrun():
    while(True):
        time.sleep(1)

if __name__=="__main__":
    t=threading.Thread(target=threadrun)
    t.start()
    sys.exit()

在Linux中启动该程序,结果并不如Python文档所述的那样,但仍可在系统中运行。那么sys.exit()到底是做什么的?

它等待线程完成,但是线程没有完成,因此它不会关闭,你是希望强制停止线程吗? - Tadhg McDonald-Jensen
3个回答

15

(对Python 2文档中Thread Objects的内容进行改写)

通常情况下,只有守护线程(忽略主线程)仍在运行时,Python程序才会退出。与程序中的初始控制线程相对应的“主线程”对象并不是守护线程。使用threading.Thread创建的线程从创建线程继承其守护状态,因此如果创建线程是主线程,则它们也将是非守护线程。

这意味着,默认情况下,如果由主程序创建和启动的任何线程在主线程终止(通过sys.exit()或简单地到达代码结尾)时仍在运行,则它们将阻止程序退出。换句话说,只有没有活着的非守护线程(即只有守护线程)剩余时,程序才会退出。

您可以通过在启动线程之前显式设置创建的任何线程对象的daemon属性为True来覆盖此默认行为。

if __name__=="__main__":
    t = threading.Thread(target=threadrun)
    t.daemon = True  # Explicitly set property.
    t.start()
    sys.exit()

这将使程序在调用 sys.exit() 时真正结束(尽管明确调用它可能并不必要,因为假定上面的代码将在脚本末尾)。


守护线程是在后台运行且不会阻止解释器退出的线程。参见守护线程解释

✶✶ 在Python 3.3中,Thread类构造函数增加了一个默认值为Nonedaemon关键字参数,这意味着从该版本开始,您可以简单地使用:

    # Sets whether the thread is daemonic via "daemon" keyword argument.
    t = threading.Thread(target=threadrun, daemon=True)

然而,通过显式属性赋值语句单独完成仍然可行,并因此成为更具版本可移植性的方法。

10
根据sys.exit()文档,sys.exit()会引发SystemExit异常:

通过引发SystemExit(status)来退出解释器。

如果SystemExit到达默认异常处理程序,它会调用handle_system_exit(),该函数基本上会推进到Py_Finalize(),进而调用Python 2中的wait_for_thread_shutdown()。 因此,sys.exit()与等待所有非守护线程终止的正常“掉落主模块底部”相同。


1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接