GIL本質是一把互斥鎖,至關於執行權限,每一個進程內都會存在一把GIL同一進程內的多線程,必須搶到GIL以後才能使用Cpython解釋器來執行本身的代碼,即同一進程下的多個線程沒法實現並行,但能夠實現併發python
Cpython解釋器下想實現並行能夠開啓多個進程安全
由於Cpython解釋器的垃圾回收機制不是線程安全的,保證了數據的安全多線程
優勢:保證了數據安全併發
缺點:單個進程下開啓多個線程只能實現併發不能實現並行app
單核或多核I/O密集型下使用:多線程性能
單核計算密集型下使用:多線程測試
多核計算密集型下使用:多進程spa
多cpu,意味着能夠有多個核並行完成計算,因此多核提高的是計算性能操作系統
每一個cpu一旦遇到I/O阻塞,仍然須要等待,因此多核對I/O操做沒什麼用處線程
對於一個程序來講不多是純IO型或者純計算型,咱們只能相對的判斷是IO密集型仍是計算密集型,來選擇多進程仍是多線程
單核狀況下:
開啓四個任務是計算密集型的,沒有多核來並行計算,開多個進程,只是徒增進程的開銷內存資源,應該使用多線程
開啓四個任務是IO密集型的,開啓多進程也是徒增,來回切換的速度還不如開啓多線程的,因此應該使用多線程
多核狀況下:
開啓四個任務是計算密集型的,多核意味着多個CPU去計算,開啓多進程能夠同一時刻去計算,因此應該使用多進程
開啓四個任務是IO密集型的,再多的核也在在等待,來回切換的速度進程不如線程的,因此應該使用多線程
from multiprocessing import Process from threading import Thread import os import time # 計算密集型 def task1(): i = 0 for line in range(110000000): i += 1 if __name__ == '__main__': print(os.cpu_count()) # 查看計算機幾核的 list1 = [] start_time = time.time() for i in range(4): p1 = Process(target=task1) # 4進程下: 17.369488954544067 # t1 = Thread(target=task1) # 4線程下: 27.991361618041992 p1.start() # t1.start() # list1.append(t1) list1.append(p1) for i in list1: i.join() end_time = time.time() print(end_time - start_time) # IO密集型 def task2(): time.sleep(1) if __name__ == '__main__': print(os.cpu_count()) start_time = time.time() list2 = [] for i in range(40): # p2 = Process(target=task2) #40進程下: 11.374541282653809 t2 = Thread(target=task2) # 40線程下: 1.010239839553833 # p2.start() t2.start() # list2.append(p2) list2.append(t2) for i in list2: i.join() end_time = time.time() print(end_time - start_time)
進程:資源單位
線程:執行單位
協程:單線程下實現併發
在I/O密集型的狀況下,使用協程提升執行效率
手動的實如今同一線程下 「 遇到I/O切換+保存狀態 」 讓操做系統誤覺得沒有I/O操做,將CPU執行權限繼續交給你
即:在單線程下實現多個任務遇到IO就切換能夠下降單線程的IO時間,從而最大限度的提高單線程的效率
gevent模塊:遇到I/O自動切換並保存狀態
使用gevent模塊中的monkey,monkey.patch_all()來監視是否遇到IO操做,再使用spawn來建立協程,使用joinall替代join,使協程運行完再結束線程,joinall中放入獲得的對象到列表中
from gevent import spawn from gevent import joinall from gevent import monkey import time # 補丁:監聽全部的任務是否有IO操做 monkey.patch_all() def task1(name): print(f'{name}開始') time.sleep(1) print(f'{name}結束') def task2(): print('task2開始') time.sleep(3) print('task2結束') def task3(): print('task3開始') time.sleep(5) print('task3結束') if __name__ == '__main__': start_time = time.time() # 建立協程 sp1 = spawn(task1,'task1') sp2 = spawn(task2) sp3 = spawn(task3) # sp1.join() # sp2.join() # sp3.join() joinall([sp1, sp2, sp3]) # 至關於 sp.join(),注意放入列表中 end_time = time.time() print(end_time - start_time) # task1開始 # task2開始 # task3開始 # task1結束 # task2結束 # task3結束 # 5.013161897659302