python學習筆記——fork()建立多進程

1 進程概述

引自 Python 多進程 fork()詳解html

1.1 進程

進程是程序的一次動態執行過程,它對應了從代碼加載、執行到執行完畢的一個完整過程。python

進程是系統進行資源分配和調度的一個獨立單位。進程是由代碼(堆棧段)、數據(數據段)、內核狀態和一組寄存器組成。 ubuntu

在多任務操做系統中,經過運行多個進程來併發地執行多個任務。因爲每一個線程都是一個能獨立執行自身指令的不一樣控制流,所以一個包含多個線程的進程也可以實現進程內多任務的併發執行。 
進程是一個內核級的實體,進程結構的全部成分都在內核空間中,一個用戶程序不能直接訪問這些數據。 併發

進程的狀態: 
建立、準備、運行、阻塞、結束。socket

1.2 進程間的通訊方式

1)文件  2)管道  3)socket  4)信號  5)信號量  6)共享內存函數

1.3 進程的建立函數

os.fork()ui

subprocessthis

processingspa

multiprocessing操作系統

 

2 建立進程

2.1 子進程的建立方式

Linux 和 Unix 操做系統提供了一個fork()函數建立新的進程,這也就意爲這該函數僅適用於Linux和Unix平臺。

fork()函數比較特殊,python的os.fork()是惟一調用一次返回兩次的函數,因操做系統將當前的進程(父進程)複製了一份新的進程(子進程),而後分別在父進程和子進程內返回。

例如:採用父子進程拷貝文件,子進程的拷貝並非從開始就就行的(除非進行設置),混亂拷貝文件可能會出現結果異常而出現錯誤。

注意:有時在一個終端會混合出現打印結果。

fork() 函數原型

Help on built-in function fork in module posix: fork(...) fork() -> pid Fork a child process. Return 0 to child process and PID of child to parent process.

fork()從本質上屬於內建函數,經過 os 模塊導入

從函數原型上看,子進程永遠返回0,而父進程則返回子進程的PID。這意味着每一個子進程的建立都會在父進程中留下標記PID(子進程身份信息),當子進程溯源其父進程時,經過getppid()就能夠找到父進程的PID

 

fork()語法:

功能:爲當前進程建立一個子進程

參數:無

返回值:0 和 子進程PID(在父進程中)

    < 0 子進程建立失敗

    = 0 在子進程中的返回值

    > 0 在父進程中的返回值

特色:

(1)子進程會繼承父進程幾乎所有代碼段(包括fork()前所定義的全部內容)

(2)子進程擁有本身獨立的信息標識,如PID

(3)父、子進程獨立存在,在各自存儲空間上運行,互不影響

(4)建立父子進程執行不一樣的內容是多任務中固定方法

關於父子進程詳見對於多進程,子進程繼承了父進程的內容fork以後子進程到底複製了父進程什麼(這裏面是C/C++內容,不過能夠借鑑其思路)

 

2.2 建立簡單的子進程:

import os pid = os.fork() if pid <0 : print("create process failed") elif pid == 0: print("this is child process") else : print("this is parent process") print("******the end*******")

運行:

this is parent process ******the end******* this is child process ******the end*******
#
this is parent process this is child process ******the end*******
******the end*******

運行的次數不一致時,會輸出不一樣結果

注:

(a)先後不一致的緣由,由於子進程和父進程獨立運行,可是打印在同一個終端上,因此終端上父子進程同時打印出來。

(b)子進程運行時是從 pid = os.fork() 下面語句執行,實際上,該語句是兩條語句, os.frok() 是建立子進程語句,而 pid =  是賦值語句,因此在建立完子進程後,下一句爲運行賦值語句。

(c)該語句中,父進程先運行,運行中,子進程也運行,但此時並不表明父進程已經運行結束;因此出現終端語句混亂

(d)幫助理解父子進程空間

import os print('python課程') os.fork() print('Python多進程')

運行結果

python課程 Python多進程 Python多進程

 在該程序中,父進程建立一個子進程,父進程打印到終端「python多進程」,同時子進程也打印到終端「python多進程」,因此是兩個「python多進程」。

(有資料顯示父進程中建立了一個子進程,子進程運行打印了一個「python多進程」,回到父進程又打印了一個「python多進程」,因此結果是打印了2個「python多進程」。注:不知道兩種描述那個符合程序運行過程,待考待查。)

2.3 添加時間調整執行順序

import os from time import sleep pid = os.fork() if pid <0 : print("create process failed") elif pid == 0: sleep(3) print("this is child process") else : sleep(1) print("this is parent process") print("******the end*******")

運行結果:

this is parent process ******the end******* this is child process ******the end*******

注:

實際上其終端顯示爲

具體緣由我目前理解爲父進程運行結束後,顯示終端待輸入命令,此時子進程沒有運行,因此會顯示上圖情形;

當將父子進程sleep()時間變換一下,則爲下面圖結果

2.4 變量在父子進程中的關係

import os from time import sleep a = 10 #父子進程中含有相同的資源,包括fork()以前的語句 pid = os.fork() if pid < 0: print('create process failed') elif pid == 0: a = 1000 #子進程將a值修改成1000
    print("This is child process") else: sleep(2) print('a = ',a) print('The pid = ',pid) print("This is parent process") print('a = ',a) print("**********the end***********")

運行結果:

This is child process a =  1000
**********the end*********** a =  10 The pid =  5495 This is parent process a =  10
**********the end***********

注:

在父進程中變量的變量a=10,而在子進程中將其綁定爲1000時,其在父進程中的綁定值並無變化。這主要是因父子進程中位於不一樣的虛擬空間所致。

2.5 父子進程PID

os.getpid() 獲取當前進程的PID號

os.getppid() 獲取當前進程父進程的PID號

import os from time import sleep pid = os.fork() if pid < 0: print("create process failed") elif pid == 0: print("my PID is",os.getpid()) #子進程PID
    print("my parent process PID is",os.getppid()) #父進程PID
    print("this is child process") else: sleep(1) print("===========================") print("the PID is",pid) #父進程中fork()返回值 = 子進程PID
    print("the parent PID is",os.getpid()) #父進程PID
    print("this is parent process")

運行結果

my PID is 5815 my parent process PID is 5814 this is child process =========================== the PID is 5815 the parent PID is 5814 this is parent process

2.6 父子進程

import os from time import sleep pid = os.fork() if pid < 0: print("create process failed") elif pid == 0: print("my PID is",os.getpid()) #子進程PID
    print("my parent process-1 PID is",os.getppid()) #父進程PID
    sleep(5) print("my parent process-2 PID is",os.getppid()) #父進程PID
    print("this is child process") else: sleep(1) print("===========================") print("the PID is",pid) #父進程中fork()返回值 = 子進程PID
    print("the parent PID is",os.getpid()) #父進程PID
    print("this is parent process")

運行

my PID is 4338 my parent process-1 PID is 4337
=========================== the PID is 4338 the parent PID is 4337 this is parent process my parent process-2 PID is 2236 this is child process

注:在子進程中,sleep(5)先後的子進程對應的父進程是不同的(PID不一致),這是因爲當父進程結束後,子進程就成了孤兒進程。

孤兒進程將被init進程(該進程號即爲子進程新的父進程PID)所收養,並由init進程對它們完成狀態收集工做。

在終端輸入top可得到PID爲2236對應信息

 COMMAND對應值爲upstart;upstart即爲ubuntux系統的一種init方式中的一種

附:目前Linux系統有三種init方式:第一種是最先的、也是廣爲流傳的System V initialization; 第二種是最近幾年提出的Upstart方式,基於事件機制,系統的全部服務和任務都是事件驅動的;最後一種是Systemd,發展最爲迅速的,大有取代Upstart之勢。本文主要是分析目前ubuntu(14.04)系統中所用的Upstart,....參看ubuntu的Upstart啓動流程ubuntu upstart簡單說明

改變程序,在父進程中增長死循環,不讓父進程退出

import os from time import sleep pid = os.fork() if pid < 0: print("create process failed") elif pid == 0: print("my PID is",os.getpid()) #子進程PID
    print("my parent process-1 PID is",os.getppid()) #父進程PID
    sleep(5) print("my parent process-2 PID is",os.getppid()) #父進程PID
    print("this is child process") else: sleep(1) print("===========================") print("the PID is",pid) #父進程中fork()返回值 = 子進程PID
    print("the parent PID is",os.getpid()) #父進程PID
    print("this is parent process") while True: pass

此時就不會發生變化,由於父進程一直處於死循環未退出狀態。

 

fork  側重於父子進程都有任務,適合於少許的子進程建立

相關文章
相關標籤/搜索