天天看點

python threading2種調用方式執行個體

1.認識GIL:

說到GIL一直是代碼專家們一直以來想要解決的問題,也是被許多程式員诟病的,下面帶領大家看下官方threading子產品document中如何去描述對于GIL這個全局解釋器鎖的:​​https://docs.python.org/3/library/threading.html​​

全局解釋器鎖

所使用的機制​​的CPython​​​解釋器來確定隻有一個線程執行的Python ​​位元組碼​​​在一個時間。通過使對象模型(包括關鍵的内置類型,例如​​dict​​)隐式安全地防止并發通路,進而簡化了CPython的實作。鎖定整個解釋器可以使解釋器更容易進行多線程處理,但會犧牲多處理器機器提供的許多并行性。

但是,某些擴充子產品(标準的或第三方的)被設計為在執行諸如壓縮或散列之類的計算密集型任務時釋放GIL。另外,在執行I / O時,始終釋放GIL。

過去建立“自由線程”解釋器(一種以更精細的粒度鎖定共享資料的解釋器)的努力并未成功,因為在常見的單處理器情況下性能會受到影響。相信克服該性能問題将使實施更加複雜,是以維護成本更高。

python threading2種調用方式執行個體

在這裡專門對全局解釋器鎖的概念引入時說了這麼一段話,第一指明了GIL造成了python解釋器一次隻有一個線程可以擷取解釋器鎖,也就是解釋器本身是自帶鎖的,誰先拿到誰就可以搶占到cpu的資源,

進而導緻了python無論一個線程怎麼去跑,都隻能最多跑滿一個cpu核心,就造成了多核cpu資源的無法利用的帶來的資源浪費,但是這是否就意味着python一無是處呢,答案肯定No!,雖然GIL對于cpu密集的支援

不是那麼的友好,但是,對于IO密集的支援恰恰是其他語言所無法比拟的,就拿asyncio這這個協程庫來講:​​https://docs.python.org/3/library/asyncio.html​​

1.第一部分認識多線程建立以及調用,上一節我講解了源碼關于多線程實作方式有兩種:第一種通過Thread類傳入可調用target對象,第二種繼承Thread類并重寫run方法:

下面就以target進行舉例:

python threading2種調用方式執行個體
python threading2種調用方式執行個體

 可以看到線程的資源搶占效果;證明GIL鎖的的确真實存在的;

先在我們如果更換t.join()到t1.start()的後面會發現,線程每次不管怎麼運作都是先執行完threading1線程,再去執行threading2線程,而這完全得益于joIn()函數:

python threading2種調用方式執行個體

我們來看源碼是怎麼解釋join()的:

等待直到線程終止。這将阻塞調用線程,直到​​join()​​被調用方法的線程終止(正常或通過未處理的異常終止),或者直到發生可選的逾時。

python threading2種調用方式執行個體

 講完join():

我們再來認識一個有趣的參數daemon->守護線程:

先看源碼:

python threading2種調用方式執行個體

 daemon用'來訓示線程是否是守護線程,必須線上程start()方法調用之前設定,否則會引發RunTimeError,當不存在活動的非守護線程時将退出python程式

示範daemon:

正常預設daemon為False:

python threading2種調用方式執行個體

 可以看到主線程運作結束後退出後子線程繼續運作并輸出了内容,

但是現在如果有個需求要求我們實作主線程退出後必須kill掉子線程那麼,如何實作這個需求,這就用到了daemon,我們隻需要設定為True:

python threading2種調用方式執行個體

 主線程運作結束後并沒有等待子線程

運作完畢就kill掉了子線程沒有輸出finsh列印就已經結束了子線程了

# 多線程實作方式二,繼承Thread 類,重寫run方法:

python threading2種調用方式執行個體

 這是一種很基本的寫法。實際開發過程我們會涉及到類的調用以及類的方法引用寫法會發生改變:

python threading2種調用方式執行個體

這裡實作了線上程外部定義一個類,其中類的方法test作為一個可調用對象傳給了繼承了Thread并重寫run方法的MyCallable類,這裡留一個思考題,對于以上重寫run你會發現我們的run是無法實作結果回調的

這就意味着,我們需要根據實際場景使用不同的子產品處理不同的需求,可以給大家一個小提示可以使用concurrent.futures或者使用  queue.Queue()來實作結果回調,因為在queue源碼中,它是基于deque來實作的而deque是線程安全的也就意味queue也是線程安全的,有興趣的可以自己去看下

j結語:

python threading2種調用方式執行個體
python threading2種調用方式執行個體