Python并发编程之多进程(一)
一、什么是進程
進程:正在進行的一個過程或者說一個任務。而負責執行任務則是cpu。
進程是資源分配的基本單位
進程有:代碼段,數據段,進程控制塊(PCB)組成
二、進程與程序的區別
程序僅僅只是一堆代碼而已,而進程指的是程序的運行過程。
舉例:
想象一位有一手好廚藝的計算機科學家正在為他的女兒烘制生日蛋糕。
他有做生日蛋糕的食譜,
廚房里有所需的原料:面粉、雞蛋、韭菜,蒜泥等。
在這個比喻中:
? 做蛋糕的食譜就是程序(即用適當形式描述的算法)
? 計算機科學家就是處理器(cpu)
? 而做蛋糕的各種原料就是輸入數據。
進程就是廚師閱讀食譜、取來各種原料以及烘制蛋糕等一系列動作的總和。
需要強調的是:同一個程序執行兩次,那也是兩個進程,比如打開暴風影音,雖然都是同一個軟件,但是一個可以播放蒼井空,一個可以播放飯島愛。
三、并發與并行
無論是并行還是并發,在用戶看來都是’同時’運行的,不管是進程還是線程,都只是一個任務而已,真是干活的是cpu,cpu來做這些任務,而一個cpu同一時刻只能執行一個任務
并發:在同一個時間段內多個任務同時進行,偽并行,即看起來是同時運行。單個cpu+多道技術就可以實現并發(并行也屬于并發)
舉例:
你是一個cpu,你同時談了三個女朋友,每一個都可以是一個戀愛任務,你被這三個任務共享,要玩出并發戀愛的效果,應該是你先跟女友1去看電影,看了一會說:不好,我要拉肚子,然后跑去跟第二個女友吃飯,吃了一會說:那啥,我去趟洗手間,然后跑去跟女友3開了個房
并行:在同一個時間點上多個任務同時進行,同時運行,只有具備多個cpu才能實現并行
單核下,可以利用多道技術,多個核,每個核也都可以利用多道技術(多道技術是針對單核而言的)
舉例:
有四個核,六個任務,這樣同一時間有四個任務被執行,假設分別被分配給了cpu1,cpu2,cpu3,cpu4, 一旦任務1遇到I/O就被迫中斷執行,此時任務5就拿到cpu1的時間片去執行,這就是單核下的多道技術,而一旦任務1的I/O結束了,操作系統會重新調用它(需知進程的調度、分配給哪個cpu運行,由操作系統說了算),可能被分配給四個cpu中的任意一個去執行
四、同步、異步、阻塞、非阻塞
同步
同步:某一個任務的執行必須依賴于另一個任務的返回結果
所謂同步,就是在發出一個功能調用時,在沒有得到結果之前,該調用就不會返回。按照這個定義,其實絕大多數函數都是同步調用。但是一般而言,我們在說同步、異步的時候,特指那些需要其他部件協作或者需要一定時間完成的任務
異步
異步:某一個任務的執行,不需要依賴于另一個任務的返回,只需要告訴另一個任務一聲
異步的概念和同步相對。當一個異步功能調用發出后,調用者不能立刻得到結果。當該異步功能完成后,通過狀態、通知或回調來通知調用者。
阻塞
阻塞:程序因為類似于IO等待、等待事件等導致無法繼續執行。
阻塞調用是指調用結果返回之前,當前線程會被掛起(如遇到io操作)。函數只有在得到結果之后才會將阻塞的線程激活。有人也許會把阻塞調用和同步調用等同起來,實際上他是不同的。對于同步調用來說,很多時候當前線程還是激活的,只是從邏輯上當前函數沒有返回而已。
非阻塞
程序遇到類似于IO操作時,不再阻塞等待,如果沒有及時的處理IO,就報錯或者跳過等其他操作
非阻塞和阻塞的概念相對應,指在不能立刻得到結果之前也會立刻返回,同時該函數不會阻塞當前線程。
五、進程的基本狀態
進程的三大基本狀態:
就緒狀態:所有進程需要的資源都獲取到了,等待著CPU的調用
執行狀態:獲取到了所有資源包括CPU,進程處于運行狀態
阻塞狀態:程停滯不再運行,放棄了CPU,進程此時處于內存里
六、multiprocessing模塊介紹
Python中的多線程無法利用多核優勢,如果想要充分地使用多核CPU的資源(os.cpu_count()查看),在Python中大部分情況需要使用多進程。Python提供了multiprocessing。
multiprocessing模塊用來開啟子進程,并在子進程中執行我們定制的任務(比如函數),該模塊與多線程模塊threading的編程接口類似。
multiprocessing模塊的功能眾多:支持子進程、通信和共享數據、執行不同形式的同步,提供了Process、Queue、Pipe、Lock等組件。
需要再次強調的一點是:與線程不同,進程沒有任何共享狀態,進程修改的數據,改動僅限于該進程內。
七、Process類的介紹
1:創建進程的類
Process([group [, target [, name [, args [, kwargs]]]]]),由該類實例化得到的對象,表示一個子進程中的任務(尚未啟動)強調: 1. 需要使用關鍵字的方式來指定參數 2. args指定的為傳給target函數的位置參數,是一個元組形式,必須有逗號2:參數介紹
group參數未使用,值始終為Nonetarget表示調用對象,即子進程要執行的任務args表示調用對象的位置參數元組,args=(1,2,'egon',)kwargs表示調用對象的字典,kwargs={'name':'egon','age':18}name為子進程的名稱3:方法介紹
p.start():啟動進程,并調用該子進程中的p.run() p.run():進程啟動時運行的方法,正是它去調用target指定的函數,我們自定義類的類中一定要實現該方法 p.terminate():強制終止進程p,不會進行任何清理操作,如果p創建了子進程,該子進程就成了僵尸進程,使用該方法需要特別小心這種情況。如果p還保存了一個鎖那么也將不會被釋放,進而導致死鎖p.is_alive():如果p仍然運行,返回Truep.join([timeout]):主線程等待p終止(強調:是主線程處于等的狀態,而p是處于運行的狀態)。timeout是可選的超時時間,需要強調的是,p.join只能join住start開啟的進程,而不能join住run開啟的進程4:屬性介紹
p.daemon:默認值為False,如果設為True,代表p為后臺運行的守護進程,當p的父進程終止時,p也隨之終止,并且設定為True后,p不能創建自己的新進程,必須在p.start()之前設置p.name:進程的名稱p.pid:進程的pidp.exitcode:進程在運行時為None、如果為–N,表示被信號N結束p.authkey:進程的身份驗證鍵,默認是由os.urandom()隨機生成的32字符的字符串。這個鍵的用途是為涉及網絡連接的底層進程間通信提供安全性,這類連接只有在具有相同的身份驗證鍵時才能成功八、Process類的使用
注意:在windows中Process()必須放到# if name == ‘main’:下
創建并開啟子進程的兩種方式
from multiprocessing import Process import osdef child_process():print("這是子進程{0},父進程是{1}".format(os.getpid(), os.getppid()))if __name__ == '__main__':child_p = Process(target=child_process)child_p.start()# child_p.join()print("這是父進程{0}".format(os.getpid())) from multiprocessing import Process import osclass ChildProcess(Process):def __init__(self):super(ChildProcess, self).__init__()def run(self):print("這是子進程{0},父進程是{1}".format(os.getpid(), os.getppid()))if __name__ == '__main__':child_p = ChildProcess()child_p.start()# child_p.join()print("這是父進程{0}".format(os.getpid()))2:進程之間的內存空間是隔離的
from multiprocessing import Process import osnum = 100def chile_process():global numnum = 0print("子進程中:{0}".format(num))if __name__ == '__main__':p = Process(target=chile_process)p.start()print("父進程中:{0}".format(num))# 父進程中:100 # 子進程中:03:Process中的join()方法
join():主進程等待,等待子進程結束
from multiprocessing import Process import os import timedef child_process():time.sleep(3)print("這是子進程")if __name__ == '__main__':p = Process(target=child_process)p.start()# p.join()print("這是主進程")# 這是主進程 # 這是子進程 # 分析:如果不加join那么則是先打印主進程中的“這是主進程”,然后等待三秒在打印“這是子進程”from multiprocessing import Process import os import timedef child_process():time.sleep(3)print("這是子進程")if __name__ == '__main__':p = Process(target=child_process)p.start()p.join()print("這是主進程") # 這是子進程 # 這是主進程 # 分析:如果加了join那么主進程會等待子進程執行完之后再執行主進程,也就是說會先等待三秒然后同時打印出“這是子進程”和“這是主進程”九、守護進程
守護進程的特點:
1:守護進程會在主進程執行完成后終止
2:設置了守護進程后,守護進程不能再開啟子進程,否則會報異常
--------------------------------------------------------------------注:如果你對python感興趣,我這有個學習Python基地,里面有很多學習資料,感興趣的+Q群:895817687--------------------------------------------------------------------from multiprocessing import Process import timedef func(name):time.sleep(1)print("我是{0}".format(name))def foo(name):time.sleep(3)print("{0}是誰".format(name))if __name__ == '__main__':p1 = Process(target=func, args=("oldwang",))p2 = Process(target=foo, args=("oldwang",))p1.daemon = True# 一定要在p.start()前設置,設置p為守護進程,禁止p創建子進程,并且父進程代碼執行結束,p即終止運行p1.start()p2.start()print("這是主進程...")# 執行結果: # 這是主進程... # oldwang是誰總結
以上是生活随笔為你收集整理的Python并发编程之多进程(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用Python递归做个多层次的文件执行
- 下一篇: Python并发编程之多进程(二)