天天看點

python中使用fork建立新的程序

fork知識入門

  python的os module中有fork()函數用于生成子程序,生成的子程序是父程序的鏡像,但是它們有各自的位址空間,子程序複制一份父程序記憶體給自己,兩個程序之間的執行是互相獨立的,其執行順序可以是不确定的、随機的、不可預測的,這點與多線程的執行順序相似。

import os
import time

try:
    forkpid = os.fork()
    time.sleep()
    print type(forkpid)
except OSError:
    sys.exit('Unable to fork.')
           

輸出如下

wayne@Z-Beatles:~/python$ python demo
<type 'int'>
<type 'int'>
           

3秒後可見fork的傳回值是兩個int型數值

python運作時建立程序

當python腳本運作,系統會生成一個新的程序。先看下面代碼:

from time import sleep
sleep()
           

因為代碼執行完後,程序就會被銷毀,是以這裡睡眠30秒,友善看到效果。再執行這個腳本檔案:

python testfork.py &
           

加上&符号,可以讓程式在背景運作,不會占用終端。輸入ps -l指令檢視程序,在電腦上輸出如下:

F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
 S                -   wait   pts/   :: bash
 S                -   poll_s pts/   :: python
 R                -   -      pts/   :: ps
           

其中第二條記錄就是剛才運作的python腳本了。

使用fork來建立一個新程序

使用fork建立一個新程序成功後,新程序會是原程序的子程序,原程序稱為父程序。如果發生錯誤,則會抛出OSError異常。

from time import sleep
import os

try:
    pid = os.fork()
except OSError, e:
    pass

sleep()
           

運作代碼後檢視程序,輸出如下:

F S   UID    PID   PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
 S                -   wait   pts/   :: bash
 S                -   poll_s pts/   :: python
 S                -   poll_s pts/   :: python
 R                -   -      pts/   :: ps
           

可以看出第二條python程序就是第一條的子程序。

fork程序後的程式流程

使用fork建立子程序後,子程序會複制父程序的資料資訊,而後程式就分兩個程序繼續運作後面的程式,這也是fork(分叉)名字的含義了。在子程序内,這個方法會傳回0;在父程序内,這個方法會傳回子程序的編号PID。可以使用PID來區分兩個程序:

import os
from time import sleep

source = 

try:
    pid = os.fork()

    if pid == :  #子程序
        source = source - 
        sleep()
        print "this is child process.source is %d" %source
    else: 
        print "this is parent process.source is %d" %source
except OSError, e:
    pass
           

上面代碼中,在子程序建立前,聲明了一個變量source,然後在子程序中自減1,最後列印出source的值,顯然父程序列印出來的值應該為10,4秒後子程序列印出來的值應該為9。

守護程序

既然子程序是父程序建立的,那麼父程序退出之後,子程序會怎麼樣呢?此時,子程序會被PID為1的程序接管,就是init程序了。這樣子程序就不會受終端退出影響了,使用這個特性就可以建立在背景執行的程式,俗稱守護程序(daemon)。

mark-守護程序

  • linux python守護程序編寫
  • Python執行個體淺談之五Python守護程序和腳本單例運作
  • Linux守護程序設計規範及python實作

Tips

  • fork()函數用來建立新的程序
  • os.fork() 會有兩次傳回值,分别是父程序和子程序的傳回值
  • 在父程序中,fork傳回的值是子程序的PID;
  • 子程序中,這個傳回值為0
  • 子程序會複制父程序的上下文
  • 父子程序并不能确定執行順序
  • os.getpid()傳回目前程序的ID,os.getppid()傳回目前程序的父程序的ID
  • os.fork() 之後,子程序一定要使用 exit() 或者 os._exit() 來退出子程序環境,建議使用 os._exit()
  • 可以使用os.waitpid(pid,0)來使父程序等待子程序執行完再執行父程序

waitpid()的使用

import os
import sys
import time 

try :
    forkPID1 = os.fork()
except OSError : # 如果作業系統不能建立程序,osfork()将會發出一個OSError異常
    sys.exit('Unable to create first child.')

if forkPID1 !=  :
    try :
        forkPID2 = os.fork() 
    except OSError :
        sys.exit('Unable to create first child.')

    if forkPID2 >  :
        print 'Parent waiting for child precesses ...\n' + \
            '\t tpid : %d , forkPID1 : %d , forkPID2 : %d' \
            % ( os.getpid() , forkPID1 , forkPID2)

        try :
            child2 = os.waitpid (forkPID2 , )[]
        except OSError :
            sys.exit("No child process with pid %d." %(forkPID2) )

        print 'Parent Child %d finished.' % child2

    elif forkPID2 ==  :
        print 'Chile2 sleeping fot 4 seconds ....\n' + \
            '\tpid : %d , forkPID1: %d , forkPID2: %d' \
            % (os.getpid() , forkPID1 , forkPID2 )
        time.sleep() #規定程序保持的休眠時間 , 以秒為機關

elif forkPID1 ==  :
    print 'Child1 sleeping for 2 seconds ....\n' + \
        '\tpid : %d , forkPID1: %d' \
        % (os.getpid() , forkPID1)
    time.sleep()
           
  • 這裡的’\’為‘反斜杠’or‘續航符’

嚴格地講, 在小括号, 方括号或大括号中的表達式 (如 定義一個 dictionary) 可以用或者不用續行符 (“\”) 分割成多行。甚至在不是必需的時候,也可以使用續行符,那可以讓代碼讀起來更容易。使用續行符隻是風格的問題。

3個示範輸出

Parent waiting for child precesses ...
     tpid :  , forkPID1 :  , forkPID2 : 
Child1 sleeping for  seconds ....
    pid :  , forkPID1: 
Chile2 sleeping fot  seconds ....
    pid :  , forkPID1:  , forkPID2: 
Parent Child  finished.

Parent waiting for child precesses ...
     tpid :  , forkPID1 :  , forkPID2 : 
Child1 sleeping for  seconds ....
Chile2 sleeping fot  seconds ....
    pid :  , forkPID1: 
    pid :  , forkPID1:  , forkPID2: 
Parent Child  finished.

Parent waiting for child precesses ...
     tpid :  , forkPID1 :  , forkPID2 : 
Child1 sleeping for  seconds ....
    pid :  , forkPID1: 
Chile2 sleeping fot  seconds ....
    pid :  , forkPID1:  , forkPID2: 
Parent Child  finished.
           

繼續閱讀