Python 内置模块之 os 之 os.for()
官方文档:https://docs.python.org/zh-cn/3.8/library/argparse.html
简介
os.fork()
是 Python 中在 Unix/Linux 系统的一个函数,它在当前进程中创建一个子进程。这个函数是 os 模块的一部分,直接调用了 Unix/Linux 系统的 fork 系统调用。fork 系统调用非常基础且强大,允许操作系统创建一个新的进程,这个新进程是调用它的进程(父进程)的副本。
注意:
os.fork()
只在 Unix/Linux 系统上可用。如果你试图在 Windows 系统上使用它,会抛出一个 AttributeError 异常。- 创建进程(尤其是在循环中)时需要谨慎,以避免无意中产生大量的进程,导致所谓的 “fork 炸弹”
示例
在我们运行 Python 程序的时候,系统会创建一个新的 python 进程。如以下代码
1 |
|
使用 fork 创建一个新的进程后,新进程是原进程的子进程,原进程为父进程。如果发生错误,则会抛出 OSError 异常。
1 |
|
运行代码,查看进程,在终端输出如下:
可以看出第二个 Python 进程就是第一个的子进程。
fork 进程后的程序流程
使用 fork 创建子进程后,子进程会复制父进程的数据信息,而后程序就分两个进程继续运行后面的程序,这也是 fork 名字的含义了。
- 在子进程内,
os.fork
会返回0; - 在父进程内,
os.fork
会返回子进程的编号PID。
可以使用 PID 来区分两个进程:
1 |
|
上面代码中,在子进程创建前,声明了一个变量 number,然后在子进程中自减 1,最后打印出 number 的值,显然父进程打印出来的值为 7,子进程打印出来的值为 6。为了明显区分父进程和子进程,让子进程睡 3 秒,这样效果就比较明显了。
既然子进程是父进程创建的,那么父进程退出之后,子进程会被 PID 为 1 的进程接管,就是init进程了。这样子进程就不会受终端退出影响了,使用这个特性就可以创建在后台执行的程序,俗称守护进程(daemon)。
底层原理
在 Python 中,os.fork()
是通过底层的操作系统调用来实现的。具体地说,它使用了 POSIX 标准中的 fork()
系统调用。
fork()
系统调用会创建一个新的进程,新进程是原始进程的一个副本,包括代码、数据和资源等。在调用 os.fork()
时,操作系统会复制当前进程的所有信息,并将这个复制的进程作为新的子进程返回给父进程。
在底层,fork()
调用的过程如下:
- 操作系统为子进程创建一个新的进程控制块(Process Control Block)来存储子进程的状态信息。
- 操作系统复制父进程的代码段、数据段和堆栈等信息到子进程的地址空间。
- 子进程开始执行从
os.fork()
后的代码,而父进程继续执行原有的代码。 - 在子进程中,
os.fork()
返回值为 0,使得子进程能够根据返回值判断自己是子进程。 - 在父进程中,
os.fork()
返回值为子进程的进程ID,使得父进程能够根据返回值判断自己是父进程。
需要注意的是,fork()
调用会在父进程和子进程中创建一个完全相同的进程映像,包括进程的状态、文件描述符等。因此,在 fork()
后,父进程和子进程是相互独立的,各自有自己的内存空间和资源。