第三十天- 程序 Process模組 空間隔離
1.程序:
程序(Process)是計算機中的程式關於某資料集合上的一次執行活動,是系統進行資源分配和排程的基本單位,是作業系統結構的基礎。在早期面向程序設計的計算機結構中,程序是程式的基本執行實體;在當代面向執行緒設計的計算機結構中,程序是執行緒的容器。程式是指令、資料及其組織形式的描述,程序是程式的實體。我們自己在python檔案中寫了一些程式碼,這叫做程式,執行這個python檔案的時候,這叫做程序。
狹義定義:程序是正在執行的程式的例項(an instance of a computer program that is being executed)
廣義定義:程序是一個具有一定獨立功能的程式關於某個資料集合的一次執行活動。它是作業系統動態執行的基本單元,在傳統的作業系統中,程序既是基本的分配單元,也是基本的執行單元。
舉例:比如py1檔案中有個變數a=1,py2檔案中有個變數a=2,他們兩個會衝突嗎?不會的,因為兩個檔案執行起來後是兩個程序,作業系統讓他們在記憶體上隔離開。
2.併發、並行:
併發:是偽並行,即看起來是同時執行。單個cpu+多道技術就可以實現併發,(並行也屬於併發)
並行:並行:同時執行,只有具備多個cpu才能實現並行
3.同步/非同步 與 阻塞和非阻塞:
1.程序狀態介紹:
(1)就緒(Ready)狀態:當程序已分配到除CPU以外的所有必要的資源,只要獲得處理機便可立即執行,這時的程序狀態稱為就緒狀態。
(2)執行/執行(Running)狀態當程序已獲得處理機,其程式正在處理機上執行,此時的程序狀態稱為執行狀態。
(3)阻塞(Blocked)狀態正在執行的程序,由於等待某個事件發生而無法執行時,便放棄處理機而處於阻塞狀態。引起程序阻塞的事件可有多種,例如,等待I/O完成、申請緩衝區不能滿足、等待信件(訊號)等。
事件請求:input、sleep、檔案輸入輸出、recv、accept
事件發生:sleep、input等完成了
時間片到了之後有回到就緒狀態,這三個狀態不斷的在轉換
2.同步/非同步 與 阻塞和非阻塞:
(1)同步阻塞形式:效率最低。拿上面的例子來說,就是你專心排隊,什麼別的事都不做。
(2)非同步阻塞形式:如果在排隊取餐的人採用的是非同步的方式去等待訊息被觸發(通知),也就是領了一張小紙條,假如在這段時間裡他不能做其它的事情,就在那坐著等著,不能玩遊戲等,那麼很顯然,這個人被阻塞在了這個等待的操作上面;
(3)同步非阻塞形式:實際上是效率低下,想象一下你一邊打著電話一邊還需要擡頭看到底隊伍排到你了沒有,如果把打電話和觀察排隊的位置看成是程式的兩個操作的話,這個程式需要在這兩種不同的行為之間來回的切換,效率可想而知是低下的。
(4)非同步非阻塞形式:效率更高,因為打電話是你(等待者)的事情,而通知你則是櫃檯(訊息觸發機制)的事情,程式沒有在兩種不同的操作中來回切換。
如,這個人突然發覺自己煙癮犯了,需要出去抽根菸,於是他告訴點餐員說,排到我這個號碼的時候麻煩到外面通知我一下,那麼他就沒有被阻塞在這個等待的操作上面,自然這個就是非同步+非阻塞的方式了。
4.multiprocessing模組(包) Process模組:
準確的說,multiprocess不是一個模組而是python中一個操作、管理程序的包。 之所以叫multi是取自multiple的多功能的意思,在這個包中幾乎包含了和程序有關的所有子模組。
process模組是一個建立程序的模組,藉助這個模組,就可以完成程序的建立
Process類中引數的介紹:
1 group引數未使用,值始終為None
2 target表示呼叫物件,即子程序要執行的任務
3 args表示呼叫物件的位置引數元組,args=(1,2,'egon',)
4 kwargs表示呼叫物件的字典,kwargs={'name':'egon','age':18}
5 name為子程序的名稱
Process類中的方法介紹:
1 p.start():啟動程序,並呼叫該子程序中的p.run()
2 p.run():程序啟動時執行的方法,正是它去呼叫target指定的函式,我們自定義類的類中一定要實現該方法
3 p.terminate():強制終止程序p,不會進行任何清理操作,如果p建立了子程序,該子程序就成了殭屍程序,使用該方法需要特別小心這種情況。如果p還儲存了一個鎖那麼也將不會被釋放,進而導致死鎖
4 p.is_alive():如果p仍然執行,返回True
5 p.join([timeout]): 主執行緒等待p終止(強調:是主執行緒處於等的狀態,而p是處於執行的狀態)。timeout是可選的超時時間,需要強調的是,p.join只能join住start開啟的程序,而不能join住run開啟的程序
1 import time 2 from multiprocessing import Process 3 4 5 def func1(n,m): 6 print('我是func1') 7 print('我是%s'%n) 8 time.sleep(1) 9 print(m) 10 11 12 def func2(): 13 time.sleep(2) 14 print('我是func2') 15 16 17 if __name__ == '__main__': 18 # target表示呼叫物件,即子程序要執行的任務 19 # args表示呼叫物件的位置引數元組,args = (1, 2,) 20 # kwargs表示呼叫物件的字典,kwargs={'name':'egon','age':18} 21 22 # p1 = Process(target=func1,args=(10,20,)) 23 p1 = Process(target=func1,kwargs={'n':10,'m':20}) 24 p2 = Process(target=func2) 25 26 p1.start() 27 p2.start() 28 print('主程式執行到這裡了') 29 p1.join() # 阻塞,等待1號子程式執行結束 30 p2.join() # 等待2號子程式執行結束 31 print('主程式執行結束')例項程式碼
5.程序的兩種建立方法和隔離驗證
兩種建立方法
1 import time 2 from multiprocessing import Process 3 4 5 def func1(): 6 print('我是func1') 7 8 # 直接建立 9 # p = Process(target=func1) 10 # p.start() 11 12 13 # 面向物件方式建立 14 class MyProcess(Process): # 自定義物件建立程序必須繼承Process父類 15 def __init__(self,n): 16 super().__init__() # super()拿到父類的__init__()避免重置父類 17 self.n = n 18 19 def run(self): # 必須有run方法,沒有雖不會報錯,但父類run裡是pass,不重寫run則為空 20 time.sleep(2) 21 print(self.n) 22 23 24 if __name__ == '__main__': # Windows下必須寫這句 避免重複呼叫 25 p = MyProcess(10) 26 p.start() 27 28 print('主程序結束')
程序之間的隔離驗證
1 import time 2 from multiprocessing import Process 3 4 num = 100 5 def func(): 6 global num 7 num = 66 8 print('我是func>>>',num) 9 10 11 if __name__ == '__main__': 12 13 # 所有的子程序非同步執行 14 p_list = [] 15 for i in range(10): 16 p = Process(target=func) 17 p.start() 18 p.join() 19 p_list.append(p) 20 21 for pp in p_list: 22 pp.join() 23 24 # 所有的子程序全部執行完之後,再執行主程序(主程序執行很快),值不一樣則證明空間隔離 25 # time.sleep(1) # 用sleep 等子程式執行完也可 26 print('主程式num:',num) 27 print('主程式執行結束')
6.程序物件的其他方法瞭解:
terminate,is_alive
1 # 程序物件的其他方法一:terminate,is_alive 2 from multiprocessing import Process 3 import time 4 5 6 class Piao(Process): 7 def __init__(self,name): 8 self.name=name 9 super().__init__() 10 11 def run(self): 12 print('%s is 打飛機' %self.name) 13 # s = input('???') # 別忘了pycharm下子程序中不能input輸入,會報錯EOFError: EOF when reading a line,因為子程序中沒有像我們主程序這樣的在pycharm下的控制檯可以輸入東西的地方 14 time.sleep(2) 15 print('%s is 打飛機結束' %self.name) 16 17 18 if __name__ == '__main__': 19 p1 = Piao('太白') 20 p1.start() 21 time.sleep(3) 22 p1.terminate() # 關閉程序,不會立即關閉,有個等著作業系統去關閉這個程序的時間,所以is_alive立刻檢視的結果可能還是存活,但是稍微等一會,就被關掉了 23 print(p1.is_alive()) # 可能結果為True 24 print('等會。。。。') 25 time.sleep(1) 26 print(p1.is_alive()) # 結果一定為Falseterminate,is_alive
name pid
1 from multiprocessing import Process 2 import time 3 import random 4 5 6 class Piao(Process): 7 def __init__(self,name): 8 # self.name=name 9 # super().__init__() #Process的__init__方法會執行self.name=Piao-1, 10 # #所以加到這裡,會覆蓋我們的self.name=name 11 12 # 為我們開啟的程序設定名字的做法 13 super().__init__() 14 self.name=name 15 16 def run(self): 17 print('%s is piaoing' %self.name) 18 time.sleep(random.randrange(1,3)) 19 print('%s is piao end' %self.name) 20 21 22 if __name__ == '__main__': 23 24 p = Piao('egon') 25 p.start() 26 print('開始') 27 print(p.pid) # 檢視pid 28 print(p.name) # 檢視namename pid