進程:
編寫完畢的代碼,在沒有運行的時候,稱之爲程序;
正在運行的代碼,就稱之爲進程;
進程,除了包含代碼以外,還有需要運行的環境等,所以和程序是有區別的;
fork() 方法創建子進程:
Python 的 os 模塊,封裝了常見的系統調用,其中就包括 fork(),可以在 python 程序中輕鬆的創建子進程;
注意:fork() 方法只能用在類 linux 系統下,不能用在 windows 系統下;
先看下面一段代碼:
# 導入 os 模塊
import os
# 調用 fork() 方法創建子進程
os.fork()
print("hello")
輸出結果:
可以發現,代碼裏只有一個輸出語句,但是實際上輸出了兩次;
這是因爲:
-
程序執行到 os.fork() 時,操作系統會創建一個新的進程(子進程),然後複製父進程的所有信息到子進程中;
-
然後父進程和子進程都會從 fork() 函數中得到一個返回值,子進程永遠返回 0,而父進程返回子進程的 id 號;
將上面代碼改成如下所示:
# 導入 os 模塊
import os
# 調用 fork() 方法創建子進程,並獲取返回值
pid = os.fork()
# 輸出 fork() 方法返回的值
print("pid:", pid)
輸出結果爲:
如果子進程中有耗時的操作,當父進程先執行結束的時候,雖然程序看似已經結束了,但是子進程並不會立刻結束,而是等子進程中的代碼執行完畢之後纔會結束:
import os
import time
# 調用 fork() 方法創建子進程,並獲取返回值
pid = os.fork()
# 輸出 fork() 方法返回的值
print("pid:", pid)
# 在子進程中模擬耗時操作
if (pid == 0):
print("=== 子進程開始 ===")
time.sleep(2) # 延遲 2 秒
print("=== 子進程結束 ===")
else:
print("=== 父進程 ===")
輸出結果:
os.getpid() 和 os.getppid():
getpid():獲取當前進程的 id(get process id);
getppid():獲取父進程的 id(get parent process id);
# 導入 os 模塊
import os
# 調用 fork() 方法創建子進程,並獲取返回值
pid = os.fork()
# 輸出 fork() 方法返回的值
print("pid:", pid)
# os.getpid():獲取當前進程 id
# os.getppid():獲取父進程 id
if (pid > 0):
print("父進程:", os.getpid())
else:
print("子進程:%d === 父進程:%d" %(os.getpid(), os.getppid()))
輸出結果:
多進程修改全局變量:
多進程中,每個進程中所有數據(包括全局變量)都各自擁有一份,互不影響;即多進程數據不共享;
import os
import time
# 定義一個全局變量
num = 10
# 創建子進程
pid = os.fork()
if (pid == 0):
# 在子進程中改變 num 的值
num += 10
print("子進程:", num)
else:
# 延遲 1 秒,是爲了保證子進程一定先執行完畢
time.sleep(1)
print("父進程:", num)
輸出結果:
多個 fork() 的情況:
先看下面一段代碼:
import os
# 第一次使用 fork 創建子進程
pid = os.fork()
if pid == 0:
print("=== 1 ===")
else:
print("=== 2 ===")
# 第二次使用 fork 創建子進程
pid = os.fork()
if pid == 0:
print("=== 11 ===")
else:
print("=== 22 ===")
輸出結果:
原理分析:
-
當程序運行到 “第一次使用 fork 創建子進程時”,此時有兩個進程,一個父進程,一個子進程;
-
我們知道,程序在創建子進程的時候,會把父進程中的所有信息全部複製到子進程中;那麼就是說 “第二次使用 fork 創建子進程” 的代碼,在父進程和子進程中各有一份;
-
所以,當父進程執行到 “第二次使用 fork 創建子進程” 的時候,又創建了一個子進程,就是說一個父進程創建了兩個子進程;此時會輸出一遍 11 和 22;
-
而當 “第一次使用 fork 創建的子進程” 也執行到 “第二次使用 fork 創建子進程” 時,子進程又創建了一個孫子進程,那麼理所當然的子進程就變成了孫子進程的父進程;那麼此時又會再輸出一遍 11 和 22;
-
所以 11 和 22 總共輸出了兩次;
-
程序中總共有 4 個進程,分別是父進程,大兒子進程,二兒子進程,以及大兒子進程的子進程;