1. 程式人生 > >linux系統編程-進程

linux系統編程-進程

end 之間 完成 有一個 等於 ESS 變量 常見 代碼

進程

現實生活中

在很多的場景中的事情都是同時進行的,比如開車的時候 手和腳共同來駕駛汽車,再比如唱歌跳舞也是同時進行的;

如下是一段視頻,邁克傑克遜的一段視頻:

http://v.youku.com/v_show/id_XMzE5NjEzNjA0.html?&sid=40117&from=y1.2-1.999.6

試想:如果把唱歌和跳舞這2件事分開以此完成的話,估計就沒有那麽好的效果了

程序中

如下程序,來模擬“唱歌跳舞” 這件事情

 11 from time import sleep
 12          
 13 def sing():
 14     for i in range(3
): 15 print(正在唱歌...%d%i) 16 sleep(1) 17 18 def dance(): 19 for i in range(3): 20 print(正在跳舞...%d%i) 21 sleep(1) 22 23 if __name__=="__main__": 24 sing()
25 dance()

運行結果如下:

正在唱歌...0
正在唱歌...1
正在唱歌...2
正在跳舞...0
正在跳舞...1
正在跳舞...2

註意!!!

  很顯然剛剛的程序並沒有完成唱歌和跳舞同事進行的要求

  如果想要實現“唱歌跳舞”同時進行,那麽就需要 一個新的方法,叫做 多任務

多任務的概念

  什麽叫做多任務呢?簡單的說,就是操作系統可以同時運行多個任務。打個比方,你一邊用瀏覽器上網,一邊在聽mp3,一邊在趕word作業,這就是多任務,至少同時有3個任務正在運行。很有很多任務悄悄的在後臺同時運行著,只是桌面上沒有顯示而已。

  現在,多核CPU已經非常普及了,但是,即使過去的單核CPU,也可以執行多任務。由於CPU執行代碼都是順序執行的,那麽單核CPU是怎麽執行多任務的呢?

  答案就是操作系統輪流讓各個任務交替執行,任務1執行0.01秒, 切換到任務2,任務2執行0.01秒,切換到任務3,執行0.01秒......,這樣反復的執行下去。表面上看,每個任務都是交替執行的,但是,由於CPU的執行速度實在是太快了,我們就感覺所有任務都在同時執行一樣。

  真正的並行執行多任務只能在多核CPU上實現,但是,由於任務數量遠遠多於CPU的核心數量,所以,操作系統也會自動把很多任務輪流調度到每個核心上執行。

  單核CPU完成多個任務的執行的原因?

  •     時間片論法
  •     優先級調度

並行和並發

  並發:看上去一直執行

  並行:真正的一起執行

進程的創建-fork

進程VS程序

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

正在運行的代碼,就稱為 進程

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

fork()

python的os模塊封裝了常見的系統調用,其中就包括fork,可以在python程序中輕松創建子進程:

 11 import os
 12      
 13 pid = os.fork()  #使用os.fork創建出一個新的進程,以下的代碼父子進程都會執行
 14      
 15 if pid == 0:
 16     print(哈哈0)
 17 else:
 18     print(哈哈1)  

運行結果如下:

哈哈1
哈哈0

還有一個例子:

 11 import os
 12 import time
 13          
 14 ret = os.fork()
 15 if ret==0:
 16     while True:
 17         print(------------1-------------)                          
 18         time.sleep(1)
 19 else:    
 20     while True:
 21         print(------------2-------------)
 22         time.sleep(1)

運行結果如下:

------------2-------------
------------1-------------
------------1-------------
------------2-------------
------------1-------------
------------2-------------
------------2-------------
------------1-------------
......

相當於程序在運行到了os.fork()時,產生了一個新的進程,ret用來接受兩個進程返回值,舊的進程執行最下面的語句,而新的進程去執行上面的語句,因為新的進程的返回值為0。之前的進程稱之為父進程,新創建出來的進程叫做子進程。

因為要分辨出父進程和子進程,所以操作系統給父進程的返回值大於0,給子進程的返回值等於0。

操作系統調度算法決定了父進程和子進程的運行順序。

說明:

  • 程序執行到os.fork(),操作系統會創建一個新的進程(子進程),然後復制父進程的所有信息到子進程中
  • 然後父進程和子進程都會從fork()函數中得到一個返回值,在子進程中這個值一定是0,而父進程中是子進程的id號

在Unix/Linux操作系統中,提供了一個fork()函數,它非常特殊。

普通的函數調用,調用一次,返回一次,但是fork()調用一次,返回兩次,因為操作系統自動把當前進程(稱為父進程)復制了一份(稱為子進程),然後,分別在父進程和子進程內返回。

子進程永遠返回0,而父進程返回子進程的ID號。

這樣做的理由是:一個父進程可以fork出很多的子進程,所以,父進程要記下每個子進程的ID,而子進程只需要調用getppid()就可以拿到父進程的ID。

fork的返回值

 11 import os
 12  
 13 ret = os.fork()
 14 print(ret)  

運行結果:

26517   #代表著父進程 
0    #代表子進程

getpid()、getppid()

getpid()獲取當前進程的值,getppid()獲取當前進程的父進程的值。

 12 import os
 13 pid = os.fork()
 14  
 15 if pid<0:
 16     print(fork調用失敗.)
 17 elif pid==0:
 18     print(我是子進程(%s),我的父進程是(%s)%(os.getpid(),os.getppid()))
 19 else:
 20     print(我是父進程(%s),我的子進程是(%s)%(os.getppid(),os.getpid()))
 21  
 22 print( 父子進程都可以執行的代碼<F8>) 

運行結果如下:

我是父進程(2774),我的子進程是(25874)
 父子進程都可以執行的代碼<F8>
我是子進程(25875),我的父進程是(25874)
 父子進程都可以執行的代碼<F8>

第二個例子:

 11 import os
12 pid = os.fork()
13 print(pid)
14
15 if pid>0:
16 print(‘父進程:%d‘%os.getpid())
17 else:
18 print(‘子進程:%d-%d‘%(os.getpid(),os.getppid()))

運行結果:

26685   #pid的返回值,操作系統為了管理給它的值,父類的返回值,就是子進程的ID號 
父進程:26684  #26684是父進程ID號
0
子進程:26685-26684  #26685是子進程ID號,子進程的父進程是26684

多進程修改全局變量

 11 import os  
 12 import time                                                                                                        
 13            
 14 num = 0    
 15            
 16 pid = os.fork()
 17            
 18 if pid==0: 
 19     num+=1 
 20     print(哈哈1------num=%d%num)
 21 else:      
 22     time.sleep(2)
 23     num+=1 
 24     print(哈哈2------num=%d%num)

運行結果如下:

哈哈1------num=1
哈哈2------num=1

說明:

  • 在多進程中,每個進程中的數據(包含全局變量)都各自擁有一份,互不影響,進程和進程之間不會數據共享

多次fork問題

如果有一個程序,有2次的fork函數調用,是否就會有3個進程呢?

 11 import os
 12 import time
 13  
 14 pid = os.fork()
 15 if pid==0:
 16     print(哈哈1)
 17 else:
 18     print(哈哈2)    #一共運行了2次
 19  
 20 pid = os.fork()
 21 if pid==0:
 22     print(哈哈3)
 23 else:
 24     print(哈哈4)    #一共運行了4次
 25  
 26 time.sleep(1)      

運行結果如下:

python@ubuntu:~/codes/liunx系統編程/01-進程$ python 05-多次fork調用.py 
哈哈2
哈哈1
哈哈4
哈哈4
哈哈3
哈哈3

說明:

技術分享圖片

父子進程的執行順序

父進程、子進程執行順序沒有規律,完全取決於操作系統的調度算法

 11 import os
 12 import time
 13 ret = os.fork()
 14      
 15 if ret==0:
 16     print(子進程)
 17     time.sleep(1)
 18     print(子進程over)    #end=""                                          
 19 else:
 20     print(父進程)

運行結果如下:

python3 04-父子進程的運行順序.py
父進程
子進程
python@ubuntu:~/codes/liunx系統編程/01-進程$ 子進程over  

因為父進程已經結束了,意味著終端已經可以開始提示了,所以當父進程一執行完,那麽終端就會立馬出來。

多任務的優點

增加程序的運行效率,例如爬蟲

multiprocessing

如果打算編寫多進程的服務程序,Unix和Linux無疑是正確的選擇。由於windows沒有fork調用,難道在 windows上無法用python編寫多進程的程序?

由於python是跨平臺的,自然也應該提供一個跨平臺的多進程支持,multiprocess模塊就是跨平臺版本的多進程模塊。

multiprocessessing模塊提供了一個Process類來代表一個進程對象,下面的例子演示了啟動一個子進程並等待其結束:

linux系統編程-進程