linux系統編程-進程
進程
現實生活中
在很多的場景中的事情都是同時進行的,比如開車的時候 手和腳共同來駕駛汽車,再比如唱歌跳舞也是同時進行的;
如下是一段視頻,邁克傑克遜的一段視頻:
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系統編程-進程