更新時間:2021-07-20 來源:黑馬程序員 瀏覽量:
在Unix/Linux操作系統(tǒng)中,通過Python的os模塊中封裝的fork()函數(shù)可以輕松地創(chuàng)建一個進程。fork()函數(shù)的聲明如下:
fork()以上函數(shù)調(diào)用后,操作系統(tǒng)會建立當前線程的副本以實現(xiàn)進程的創(chuàng)建,此時原有的進程被稱為父進程,復制的進程被稱為子進程。需要注意的是,fork()函數(shù)的一次調(diào)用產(chǎn)生兩個結(jié)果:若當前執(zhí)行是父進程,fork()函數(shù)返回子進程ID;若當前執(zhí)行的進程是子進程,fork()函數(shù)返回0。如果fork()函數(shù)調(diào)用時出現(xiàn)錯誤,進程創(chuàng)建失敗,將返回一個負值。
下面使用fork()函數(shù)創(chuàng)建一個子進程,讓父進程和子進程分別執(zhí)行不同的任務,代碼如下:
import os import time value = os.fork() # 創(chuàng)建子進程 if value == 0: # 子進程執(zhí)行if分支語句 print('---子進程---') time.sleep(2) else: # 父進程執(zhí)行else分支語句 print('---父進程---') time.sleep(2)
以上程序調(diào)用fork()函數(shù)創(chuàng)建子進程,使用變量value記錄fork()的返回值,并根據(jù)fork()的返回結(jié)果區(qū)分父進程與子進程,為這兩個進程分派不同的任務:當value為0時,說明當前進程是子進程,執(zhí)行if分支中的語句;當value不為0時,說明此時系統(tǒng)調(diào)度的是父進程,執(zhí)行else分支中的語句。進程創(chuàng)建與程序執(zhí)行的具體流程如圖1所示。
圖1 使用fork()函數(shù)創(chuàng)建進程
程序執(zhí)行一次的結(jié)果如下所示:
---父進程--- ---子進程---
觀察此次結(jié)果可以推測,系統(tǒng)先調(diào)度父進程,再調(diào)度子進程,但實際上,子進程和父進程執(zhí)行的順序是不確定的,會受到時間片、調(diào)度優(yōu)先級或其它因素的影響。
若程序中順序調(diào)用兩次fork()函數(shù),那么第一次調(diào)用fork()后系統(tǒng)中存在的兩個進程都會調(diào)用第二個fork()函數(shù)創(chuàng)建新進程,兩次fork()函數(shù)后進程的變化如圖2所示。
圖2 進程的變化
從圖2中可以看出,“父進程1”和“子進程1”再次復制出兩個子進程,“父進程1”成為“子進程2”的父進程,“子進程1”成為“子進程3”的父進程,變成“父進程2”。
下面使用fork()函數(shù)創(chuàng)建3個子進程,代碼如下:
import os import time print('---第一次fork()調(diào)用---') value = os.fork() # 創(chuàng)建子進程,此時進程的總數(shù)量為2 if value == 0: # 子進程執(zhí)行if分支語句 print('---進程1---') time.sleep(2) else: # 父進程執(zhí)行else分支語句 print('---進程2---') time.sleep(2) print('---第二次fork()調(diào)用---') value = os.fork() # 創(chuàng)建子進程,此時進程的總數(shù)量為4 if value == 0: # 子進程執(zhí)行if分支語句 print('---進程3---') time.sleep(2) else: # 父進程執(zhí)行else分支語句 print('---進程4---') time.sleep(2)
程序執(zhí)行的結(jié)果如下:
---第一次fork()調(diào)用--- ---進程2--- ---進程1--- ---第二次fork()調(diào)用--- ---進程4--- ---進程4--- ---進程3--- ---進程3---
由執(zhí)行結(jié)果可知,程序在第一次調(diào)用fork()函數(shù)后創(chuàng)建了一個子進程,此時共有父進程和子進程執(zhí)行下面的代碼,分別輸出 “---進程2---”和“---進程1---”;程序在第二次調(diào)用fork()函數(shù)后又創(chuàng)建了兩個新的子進程,此時共有兩個父進程和兩個子進程執(zhí)行下面的代碼,分別輸出兩次“---進程4---”和“---進程3---”。
獲取當前進程的ID
進程ID是進程的唯一標識,為了便于管理系統(tǒng)中的進程,os模塊提供了os.getpid()函數(shù)和os.getppid()函數(shù)來分別獲取當前進程id和當前進程父進程的id,示例代碼如下:
import os process = os.fork() # 創(chuàng)建子進程 if process == 0: # 獲取父進程的ID print('我是子進程-%d,父進程是%d'%(os.getpid(), os.getppid())) else: print('我是父進程-%d, 子進程是%d'%(os.getpid(), process)) # 獲取當前線程的ID
程序運行的結(jié)果如下:
我是父進程-2497, 子進程是2498 我是子進程-2498,父進程是2497