linux中的fork方法(python)
前言:
Unix/Linux操作系統提供了一個fork()系統調用,它非常特殊。普通的函數調用,調用一次,返回一次,但是fork()調用一次,返回兩次,因為操作系統自動把當前進程(稱為父進程)復制了一份(稱為子進程),然后,分別在父進程和子進程內返回。
子進程永遠返回0,而父進程返回子進程的ID。這樣做的理由是,一個父進程可以fork出很多子進程,所以,父進程要記下每個子進程的ID,而子進程只需要調用getppid()就可以拿到父進程的ID。
Python的os模塊封裝了常見的系統調用,其中就包括fork,可以在Python程序中輕松創建子進程。
一、fork入門知識
?????一個進程,包括代碼、數據和分配給進程的資源。fork()函數通過系統調用創建一個與原來進程幾乎完全相同的進程,
也就是兩個進程可以做完全相同的事,但如果初始參數或者傳入的變量不同,兩個進程也可以做不同的事。
??? 一個進程調用fork()函數后,系統先給新的進程分配資源,例如存儲數據和代碼的空間。然后把原來的進程的所有值都
復制到新的新進程中,只有少數值與原來的進程的值不同。相當于克隆了一個自己。
???? 我們來看一個例子:
import os print('Process (%s) start...' % os.getpid()) # Only works on Unix/Linux/Mac: count = 0 pid = os.fork() if pid == 0:print('I am child process (%s) and my parent is %s.' % (os.getpid(), os.getppid()))count += 1print("count:", count) else:print('I (%s) just created a child process (%s).' % (os.getpid(), pid))count += 1print("count:", count)輸出:
Process (11844) start...
I (11844) just created a child process (11845).
count: 1
I am child process (11845) and my parent is 11844.
count: 1
?
在語句pid = os.fork()之前,只有一個進程在執行這段代碼,但在這條語句之后,就變成兩個進程在執行了,這兩個進程的幾乎完全相同,
將要執行的下一條語句都是print("pid:",pid)……
??? 為什么兩個進程的fpid不同呢,這與fork函數的特性有關。
fork調用的一個奇妙之處就是它僅僅被調用一次,卻能夠返回兩次,它可能有三種不同的返回值:
??? 1)在父進程中,fork返回新創建子進程的進程ID;
??? 2)在子進程中,fork返回0;
??? 在fork函數執行完畢后,如果創建新進程成功,則出現兩個進程,一個是子進程,一個是父進程。在子進程中,fork函數返回0,在父進程中,
fork返回新創建子進程的進程ID。我們可以通過fork返回的值來判斷當前進程是子進程還是父進程。
????引用一位網友的話來解釋fpid的值為什么在父子進程中不同:
? -? ? “其實就相當于鏈表,進程形成了鏈表,父進程的fpid(p 意味point)指向子進程的進程id,因為子進程沒有子進程,所以其fpid為0.
創建新進程成功后,系統中出現兩個基本完全相同的進程,這兩個進程執行沒有固定的先后順序,哪個進程先執行要看系統的進程調度策略。
??? 每個進程都有一個獨特(互不相同)的進程標識符(process ID),可以通過getpid()函數獲得,還有一個記錄父進程pid的變量,可以通過getppid()函數獲得變量的值。
fork執行完畢后,出現兩個進程,
有人說兩個進程的內容完全一樣啊,怎么打印的結果不一樣啊,那是因為判斷條件的原因,上面列舉的只是進程的代碼和指令,還有變量啊。
??? 執行完fork后,進程1的變量為count=0,fpid!=0(父進程)。進程2的變量為count=0,fpid=0(子進程),這兩個進程的變量都是獨立的,
存在不同的地址中,不是共用的,這點要注意。可以說,我們就是通過fpid來識別和操作父子進程的。
??? 還有人可能疑惑為什么不是從#include處開始復制代碼的,這是因為fork是把進程當前的情況拷貝一份,執行fork時,進程已經執行完了int count=0;
fork只拷貝下一個要執行的代碼到新的進程。
二、fork進階知識
????先看一份代碼:
import os print("i son/pa ppid pid fpid/n") #ppid指當前進程的父進程pid #pid指當前進程的pid, #fpid指fork返回給當前進程的值 for i in range(2):fpid = os.fork()if fpid == 0:print("%d child %4d %4d %4d" % (i, os.getppid(), os.getpid(), fpid))else:print("%d parent %4d %4d %4d" % (i, os.getppid(), os.getpid(), fpid))輸出:
i son/pa ppid pid ?fpid/n
0 parent 12137 12333 12334
0 child ?12333 12334 ? ?0
1 parent 12137 12333 12335
1 parent 12333 12334 12336
1 child ?12333 12335 ? ?0
1 child ?12334 12336 ? ?0? ? ?
?
?? 這份代碼比較有意思,我們來認真分析一下:
????第一步:在父進程中,指令執行到for循環中,i=0,接著執行fork,fork執行完后,系統中出現兩個進程,分別是p12333和p12334
(后面我都用pxxxx表示進程id為xxxx的進程)。可以看到父進程p12333的父進程是p12334,子進程p12334的父進程正好是p12333。我們用一個鏈表來表示這個關系:
? ? p12137->p12333->p12334
第一次fork后,p12333(父進程)的變量為i=0,fpid=12334(fork函數在父進程中返向子進程id),代碼內容為:
?p12334(子進程)的變量為i=0,fpid=0(fork函數在子進程中返回0),代碼內容為:
for i in range(2):fpid = os.fork() # 執行完畢,i=0,fpid=0if fpid == 0:print("%d child %4d %4d %4d" % (i, os.getppid(), os.getpid(), fpid))else:print("%d parent %4d %4d %4d" % (i, os.getppid(), os.getpid(), fpid))所以打印出來的結果是:
0 parent 12137 12333 12334
0 child ?12333 12334 ? ?0
第二步:假設父進程p12333先執行,當進入下一個循環時,i=1,接著執行fork,系統中又新增一個進程p12335,對于此時的父進程,
p12137->p12333(當前進程)->p12335(被創建的子進程)。
??? 對于子進程p12334,執行完第一次循環后,i=1,接著執行fork,系統中新增一個進程p12336,對于此進程,
p12333->p12334(當前進程)->p12336(被創建的子進程)。
從輸出可以看到p12334原來是p12333的子進程,現在變成p12336的父進程。父子是相對的,這個大家應該容易理解。只要當前進程執行了fork,該進程就變成了父進程了,就打印出了parent。
? 所以打印出結果是:
???1 parent 12137 12333 12335
? ?1 parent 12333 12334 12336
????第三步:第二步創建了兩個進程p12335,p12336,這兩個進程執行完print函數后就結束了,因為這兩個進程無法進入第三次循環,無法fork,其他進程也是如此。
??? 以下是p12335,p123356打印出的結果:
????1 child ?12333 12335 ? ?0
? ? 1 child ?12334 12336 ? ?0? ? ?
??? 總結一下,這個程序執行的流程類似如下:
?這個程序最終產生了3個子進程,執行過6次print()函數。
??? 我們再來看一份代碼:
輸出:
?i son/pa ppid pid ?fpid/n
parent
son
parent
parent
parent
parent
son
parent
son
son
parent
son
?
?這里就不做詳細解釋了,只做一個大概的分析。
????for????????i=0???????? 1?????????? 2
??????????????father???? father???? father
????????????????????????????????????????son
????????????????????????????son?????? father
????????????????????????????????????????son
???????????????son?????? father???? father
????????????????????????????????????????son
????????????????????????????son?????? father
????????????????????????????????????????son
?
其中每一行分別代表一個進程的運行打印結果。
總結一下規律,對于這種N次循環的情況,執行printf函數的次數為2*(1+2+4+……+2N-1)次,創建的子進程數為1+2+4+……+2N-1個。
?
fork的內容就先到這里,
參考:
? ? ? ? (1)、https://www.cnblogs.com/jycboy/p/l_fork.html
? ? ? ? ?(2)、https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431927781401bb47ccf187b24c3b955157bb12c5882d000
總結
以上是生活随笔為你收集整理的linux中的fork方法(python)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: shiro学习(18):使用注解实现权限
- 下一篇: Linux下PHP+MySQL+Core