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