学科分类
目录

通过fork()函数创建进程

在Unix/Linux操作系统中,通过Python的os模块中封装的fork()函数可以轻松地创建一个进程。fork()函数的声明如下:

fork()

以上函数调用后,操作系统会建立当前线程的副本以实现进程的创建,此时原有的进程被称为父进程,复制的进程被称为子进程。需要注意的是,fork()函数的一次调用产生两个结果:若当前执行是父进程,fork()函数返回子进程ID;若当前执行的进程是子进程,fork()函数返回0。如果fork()函数调用时出现错误,进程创建失败,将返回一个负值。

下面使用fork()函数创建一个子进程,让父进程和子进程分别执行不同的任务,代码如下:

import os
import time
value = os.fork()             # 创建子进程
if value == 0:                 # 子进程执行if分支语句
  print('---子进程---')
  time.sleep(2)
else:                       # 父进程执行else分支语句
  print('---父进程---')
  time.sleep(2)

以上程序调用fork()函数创建子进程,使用变量value记录fork()的返回值,并根据fork()的返回结果区分父进程与子进程,为这两个进程分派不同的任务:当value为0时,说明当前进程是子进程,执行if分支中的语句;当value不为0时,说明此时系统调度的是父进程,执行else分支中的语句。进程创建与程序执行的具体流程如图1所示。

img

图1 使用fork()函数创建进程

程序执行一次的结果如下所示:

---父进程---
---子进程---

观察此次结果可以推测,系统先调度父进程,再调度子进程,但实际上,子进程和父进程执行的顺序是不确定的,会受到时间片、调度优先级或其它因素的影响。

若程序中顺序调用两次fork()函数,那么第一次调用fork()后系统中存在的两个进程都会调用第二个fork()函数创建新进程,两次fork()函数后进程的变化如图2所示。

img

图2 进程的变化

从图2中可以看出,“父进程1”和“子进程1”再次复制出两个子进程,“父进程1”成为“子进程2”的父进程,“子进程1”成为“子进程3”的父进程,变成“父进程2”。

下面使用fork()函数创建3个子进程,代码如下:

import os
import time
print('---第一次fork()调用---')
value = os.fork()      # 创建子进程,此时进程的总数量为2
if value == 0:          # 子进程执行if分支语句
    print('---进程1---')
    time.sleep(2)
else:                     # 父进程执行else分支语句
    print('---进程2---')
    time.sleep(2)
print('---第二次fork()调用---')
value = os.fork()       # 创建子进程,此时进程的总数量为4
if value == 0:           # 子进程执行if分支语句
    print('---进程3---')
    time.sleep(2)
else:                      # 父进程执行else分支语句
    print('---进程4---')
    time.sleep(2)

程序执行的结果如下:

---第一次fork()调用---
---进程2---
---进程1---
---第二次fork()调用---
---进程4---
---进程4---
---进程3---
---进程3---

由执行结果可知,程序在第一次调用fork()函数后创建了一个子进程,此时共有父进程和子进程执行下面的代码,分别输出 “---进程2---”和“---进程1---”;程序在第二次调用fork()函数后又创建了两个新的子进程,此时共有两个父进程和两个子进程执行下面的代码,分别输出两次“---进程4---”和“---进程3---”。

多学一招:获取当前进程的ID

进程ID是进程的唯一标识,为了便于管理系统中的进程,os模块提供了os.getpid()函数和os.getppid()函数来分别获取当前进程id和当前进程父进程的id,示例代码如下:

import os
process = os.fork() # 创建子进程
if process == 0: 
    # 获取父进程的ID 
    print('我是子进程-%d,父进程是%d'%(os.getpid(), os.getppid()))  
else:
    print('我是父进程-%d, 子进程是%d'%(os.getpid(), process)) # 获取当前线程的ID

程序运行的结果如下:

我是父进程-2497, 子进程是2498
我是子进程-2498,父进程是2497
点击此处
隐藏目录