__init__
__new__
__str__
__len__
__del__
__eq__
__hash__
try...except...
try...except...except...
try...except...else...
finally
咱們打開任務管理器,就會發現,同一時刻用不少程序在運行。這種是的計算機能夠同時處理多個任務的現象就是多任務處理。數組
有了多任務處理,咱們才能作到在聽歌的同時使用QQ聊天、辦公和下載文件。併發
多任務處理的幾個重要概念app
程序,是一個指令的集合,也就是咱們寫的一套代碼。異步
進程則是指正在執行的程序。換句話說,當你運行一個程序,你就啓動了一個進程。async
操做系統輪流讓各個任務交替執行。因爲CPU的執行速度實在是太快了,咱們感受就像全部任務都在同時執行同樣。函數
多進程,就是讓多個程序同時運行。多進程中,每一個進程中全部數據(包括全局變量)都各擁有一份,互不影響。測試
程序開始運行時,會首先建立一個主進程(父進程)操作系統
在主進程下,咱們能夠建立新的進程,也就是子進程。code
子進程依賴於主進程,若是主進程結束,程序會退出,子進程也就自動終止。
Python提供了很是好用的多進程包multiprocessing。藉助這個包,能夠輕鬆完成單進程到併發執行的轉換:
from multiprocessing import Process def land_occupation(name): print(f'{name}佔領銅鑼灣') def grab_the_ground(): print('搶佔鉢蘭街') # Windows系統須要這行代碼避免迭代導入的異常 if __name__ == '__main__': print('主進程啓動,幫派創建') haonan = Process(target=land_occupation, args=('陳浩南',), name='陳浩南佔地盤的子進程') # target表示調用的方法,args表示調用方法的位置參數元組 # 須要注意的是,若是元組只有一個元素,括號中須要加一個逗號 shisanmei = Process(target=grab_the_ground, name='十三妹搶地盤的子進程') print(haonan.name, shisanmei.name) print(haonan.pid, shisanmei.pid) haonan.start() shisanmei.start() print(haonan.pid, shisanmei.pid) haonan.join() shisanmei.join() print('程序結束') 輸出的結果爲: 主進程啓動,幫派創建 陳浩南佔地盤的子進程 十三妹搶地盤的子進程 None None 19932 19160 搶佔鉢蘭街 陳浩南佔領銅鑼灣 程序結束
在上面的代碼中,咱們把建立的進程和調用進程的代碼都寫到了if __name__ == '__main__':
的子句中。
這是由於在Windows中,子進程會自動import啓動它的文件。而在import時,文件中的代碼會被自動執行。當執行到建立子進程的代碼時,又要從新導入本身。這就陷入了一個導入本身的死循環,而後就會報錯。
爲了不報錯,咱們把這些代碼放到if __name__ == '__main__':
的子句中,這樣當建立子進程時,導入代碼就不會從新加載建立子進程的語句了。
不過最好仍是將操做多進程的代碼封裝到函數中,這樣會避免不少麻煩。
Process(target, name, args)
參數介紹
Process類經常使用方法
.start()
:啓動進程,並調用子進程中的.run()
方法.run()
:進程啓動時調用的方法,正是它去調用target參數指定的函數。.terminate()
:(瞭解便可)強制終止進程,不會進行任何清理操做,進程會一直佔用內存空間.is_alive()
:若是進程仍在運行,返回True,不然返回False。用來判斷進程是否還在運行.join([timeout])
:中近程等待子進程終止,timeout時可選的超時時間Process類經常使用屬性:
全局變量在多個進程中是不共享的。進程之間的數據相互獨立,默認狀況下不會相互影響:
from multiprocessing import Process num = 10 def r1(): global num num += 5 print('在進程一中,num的值爲:', num) def r2(): global num num += 10 print('在進程二中,num的值爲:', num) if __name__ == '__main__': p1 = Process(target=r1) p2 = Process(target=r2) p1.start() p2.start() p1.join() p2.join() print('程序結束前,主進程中num的值爲:', num) 輸出的結果爲: 在進程一中,num的值爲: 15 在進程二中,num的值爲: 20 程序結束前,主進程中num的值爲: 10
須要注意的是,每次建立進程對象時,都會import當前文件。這就致使在if __name__ == '__main__'
語句以後對num進行的修改操做不會被加載到進程對象的內存中。換句話說,子進程可以加載全局變量在if __name__ == '__main__'
語句以外的修改,卻沒法加載其內部的修改:
from multiprocessing import Process num = 10 def r1(): global num num += 5 print('在進程一中,num的值爲:', num) def r2(): global num num += 10 print('在進程二中,num的值爲:', num) # 在外部修改全局變量num num += 500 if __name__ == '__main__': # 在內部修改全局變量 num += 1000 p1 = Process(target=r1) p2 = Process(target=r2) p1.start() p2.start() p1.join() p2.join() print('程序結束前,主進程中num的值爲:', num) 輸出的結果爲: 在進程一中,num的值爲: 515 在進程二中,num的值爲: 520 程序結束前,主進程中num的值爲: 1510
在子進程中,1000都沒有被加上,可是500被加上了。由此能夠驗證前面的觀點。
除了直接使用Process建立類對象以外,咱們還能夠本身寫進程對象,只需繼承Process類便可:
from multiprocessing import Process import time class ClockProcess(Process): # 重寫的run方法就是咱們要執行的子進程方法 def run(self): n = 5 while n > 0: print(n) time.sleep(1) n -= 1 if __name__ = '__main__': p = ClockProcess() p.start() p.join() 輸出的結果爲: 5 4 3 2 1 上面的內容每隔一秒鐘打印出一個
進程池用來建立多個進程。
當須要建立的子進程數量很少時,能夠直接利用multiprocessing中的Process動態生成多個進程。但若是咱們須要建立大量的進程,若是手動建立那工做量將極其巨大。並且會產生不少的重複代碼。此時,就能夠用到multiprocessing模塊提供的Pool來實現批量建立多個進程。
初始化Pool時,能夠指定一個最大進程數。當有新的請求提交到Pool中時,若是池尚未滿,那麼就會建立一個新的進程用來執行該請求;若是池中的進程數已經達到指定的最大值,那麼該請求就會等待,直到池中有進程結束,纔會建立新的進程來執行。
建立進程池的基本辦法爲:
from multiprocessing import Pool import time def r1(): print('這裏是進程一呀~') time.sleep(5) def r2(): print('這裏是進程二呀~') time.sleep(3) if __name__ == '__main__': # 定義一個進程池,參數爲最大進程數,默認大小爲CPU核數 po = Pool() for i in range(100): # apply_async選擇要調用的目標,每次循環會用空出來的子進程去調用目標 po.apply_async(r1) po.apply_async(r2) # 進程池關閉後再也不接收新的請求 po.close() # 等待po中全部子進程結束,必須放在close後面 po.join() # 在多進程中,主進程通常用來等待,真正的任務都在子進程中
multiprocessing.Pool
經常使用函數解析
apply_async(func[, args[, kwargs]])
:使用非阻塞方式調用func(並行執行,阻塞方式必須等待上一個進程退出才能執行下一個進程)。args爲傳遞給func的位置參數,kwargs爲傳遞給func 的關鍵字參數apply(func[, args[, kwargs]])
(瞭解便可)使用阻塞方式調用func,效果與單進程相同close()
:關閉進程池,使其再也不接收新的任務join()
:主進程阻塞,等待子進程的退出,必須在close或terminate以後使用