在Linux操作系统中,当进程退出时,它会与操作系统进行一系列的交互来释放资源、关闭文件描述符等。os._exit(), sys.exit(), 和 exit() 这三个函数虽然都可以用来结束Python程序,但它们与操作系统交互的方式存在差异:
os._exit():
- os._exit() 调用的是操作系统级别的退出函数,直接告诉操作系统立即终止当前进程。在Linux中,它对应的是 _exit 系统调用。
- 当调用 os._exit() 时,进程会立即终止,操作系统会负责回收进程占用的所有资源,如内存和文件描述符。这个调用不会处理Python的清理工作,如对象的析构函数、finally 块中的代码,或者标准I/O缓冲区的刷新等。
- 由于是直接与操作系统交互,不经过任何语言层面的清理,这种退出方式是非常迅速但也比较“粗暴”的。
sys.exit():
- sys.exit() 实际上会引发一个 SystemExit 异常。如果这个异常没有被捕获,那么Python解释器会开始进行一系列的清理操作,包括执行对象的析构函数、处理finally块等。
- 一旦Python层面的清理完成,解释器会向操作系统发送退出信号。这时,操作系统接管进程,回收分配给进程的所有资源。
- 在操作系统层面,sys.exit() 与正常程序结束的行为是一致的,都会经过正常的资源回收和清理过程。
- 这段代码是Python内部用C语言实现的sys.exit()函数的核心部分,位于Python源代码的sysmodule.c文件中。sys_exit_impl函数实现了在C层面触发Python的SystemExit异常,调用_PyErr_SetObject函数,在当前线程状态tstate上设置一个异常。这个异常是PyExc_SystemExit(也就是Python中的SystemExit异常),附加的值是status参数。这实质上是在当前Python环境中触发了一个SystemExit异常,并将status作为异常的值。允许Python代码捕获这个异常并进行相应的异常处理或清理工作
static PyObject *
sys_exit_impl(PyObject *module, PyObject *status)
{
/* Raise SystemExit so callers may catch it or clean up. */
PyThreadState *tstate = _PyThreadState_GET();
_PyErr_SetObject(tstate, PyExc_SystemExit, status);
return NULL;
}
exit():
- exit() 函数主要用于交互式解释器,并不是设计用于程序中。它的底层实现实际上是通过引发 SystemExit 异常来实现的,因此,其行为与 sys.exit() 类似。
- 使用 exit() 时,Python解释器同样会进行一系列清理操作,然后才通知操作系统终止进程。
- 在脚本或程序中调用 exit() 可能会引发一个异常,因为它本质上是一个内置的帮助函数,不是设计来被脚本调用的。
- exit实现方式:创建一个 Quitter 类的实例并调用它时,它会关闭标准输入流并退出程序,同时提供一种通过字符串表示来提示用户如何使用它的方式。例如,如果你创建了一个 Quitter 实例 q = Quitter('quit', 'EOF'),那么当你输入 q 时,它会提示 "Use quit() or EOF to exit",而当你调用 q() 时,程序会尝试关闭标准输入并退出。
class Quitter(object):
def __init__(self, name, eof):
self.name = name
self.eof = eof
def __repr__(self):
return 'Use %s() or %s to exit' % (self.name, self.eof)
def __call__(self, code=None):
try:
sys.stdin.close()
except:
pass
raise SystemExit(code)