前言:
上vip課的時候每次講到框架的執行,就會有好學的同學問用多線程怎麼執行,然後我每次都會說在測開課程會詳細講解,這並不是套路,因為如果你不理解多線程,不清楚什麼時候該用什麼時候不該用,就會適得其反。今天我們就來聊一聊多線程這個燙手的山芋。
一、python執行慢的原因
1、動態類型語言,邊解釋邊執行。
2、GIL鎖無法使用多核CPU並發執行。
二、什麼是GIL鎖
1、全局解釋器鎖(Global Interpreter Lock),是電腦程式設計語言計時器用於同步線程的一種機制,它使得任何時刻僅有一個線程在執行。
即使在多核CPU上,使用GIL的解釋器也只允許同一時間執行一個線程。
2、你可以理解為這是python設計上的一個Bug,但是因為重構成本太高,龜叔也沒打算修復了。
3、那麼多線程就沒有用了嗎?當然不是,多線程可以用於IO密集型任務。
三、CPU密集型
阿里雲開發者社區的解釋:CPU密集型(CPU-bound) CPU密集型也叫計算密集型,指的是系統的硬碟、內存性能相對CPU要好很多,此時,系統運作大部分的狀況是CPU Loading 100%,CPU要讀/寫I/O(硬碟/內存),I/O在很短的時間就可以完成,而CPU還有許多運算要處理,CPU Loading很高。
說人話:做某件事情的時候CPU很忙,磁碟/內存讀取很閒,這個事情就叫CPU密集型任務。
四、IO密集型
阿里雲開發者社區的解釋:IO密集型指的是系統的CPU性能相對硬碟、內存要好很多,此時,系統運作,大部分的狀況是CPU在等I/O (硬碟/內存) 的讀/寫操作,此時CPU Loading並不高。
說人話:做某件事情的時候磁碟/內存讀取很忙,CPU很閒,這個事情就叫IO密集型任務。
五、什麼是多線程
百度百科的解釋:多線程(multithreading),是指從軟體或者硬體上實現多個線程並發執行的技術。
六、多線程使用場景
1、用於IO密集型任務
七、進入主題上代碼
import requests
import time
import Threading
#幹活函數,請求測試派,其他的啥都不干
def get_url(url):
requests.get(url=url)
#單線程實現,訪問測試派50次
def single(url):
for i in range(50):
get_url(url)
#多線程實現,訪問測試派50次
def create_multi(url):
threads = []
for i in range(50):
#創建子線程
th = threading.Thread(target=get_url,args=(url,))
threads.append(th)
#啟動子線程
for val in threads:
val.start()
#主線程等待子線程執行結束再結束
for val in threads:
val.join()
if __name__ == '__main__':
url = "http://testingpai.com/recent"
#單線程執行時間統計
start = time.time()
single(url)
end=time.time()
print("單線程耗時:",end - start)
print("="*30)
#多線程執行時間統計
start = time.time()
create_multi(url)
end=time.time()
print("多線程耗時:",end - start)
輸出:
單線程耗時:27.86112666130066
==============================
多線程耗時: 19.54499316215515
►►►
多線程的創建方式
上面我們講了多線程的使用場景,通過一個簡單的例子了解了多線程在IO密集型任務中確實能提高代碼執行效率,接下來我們聊一聊多線程的創建。
一、實例化Thread類創建
import requests
import threading
#幹活函數,請求測試派,其他的啥都不干
def get_url(url):
requests.get(url=url)
if __name__ == '__main__':
url = "http://testingpai.com/recent"
threads = []
for i in range(50):
#創建子線程
th = threading.Thread(target=get_url,args=(url,))
threads.append(th)
#啟動子線程
for val in threads:
val.start()
#主線程等待子線程執行結束再結束
for val in threads:
val.join()
二、繼承Thread重寫run方法創建
import requests
import threading
class TestThreading(threading.Thread):
def __init__(self):
#調用父類初始化函數進行必要的初始化
super().__init__()
#重寫run方法
def run(self):
thread_name = threading.current_thread().name
thread_id = threading.current_thread().ident
print('子線程id={},子線程名稱={}:'.format(thread_id, thread_name))
print("幹活的函數邏輯寫在這裡")
res = requests.get(url="http://testingpai.com/recent")
print(res)
if __name__ == '__main__':
#啟動子線程
for i in range(3):
th = TestThreading()
th.start()