Python學習筆記(二十四):在 linux 系統下使用 fork() 創建子進程


進程:

編寫完畢的代碼,在沒有運行的時候,稱之爲程序;

正在運行的代碼,就稱之爲進程;

進程,除了包含代碼以外,還有需要運行的環境等,所以和程序是有區別的;

 

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 個進程,分別是父進程,大兒子進程,二兒子進程,以及大兒子進程的子進程;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章