python線程同步原語--源碼閱讀

来源:https://www.cnblogs.com/thomson-fred/archive/2018/11/21/9992969.html
-Advertisement-
Play Games

前面兩篇文章,寫了python線程同步原語的基本應用。下麵這篇文章主要是通過閱讀源碼來瞭解這幾個類的內部原理和是怎麼協同一起工作來實現python多線程的。 相關文章鏈接:python同步原語--線程鎖 python--線程同步原語 一、關於Condition類 Condition的用法: 用來記錄 ...


前面兩篇文章,寫了python線程同步原語的基本應用。下麵這篇文章主要是通過閱讀源碼來瞭解這幾個類的內部原理和是怎麼協同一起工作來實現python多線程的。

相關文章鏈接:python同步原語--線程鎖 

                      python--線程同步原語                            

 

一、關於Condition

Condition的用法:

用來記錄線程的狀態變數

查看Condition的源碼,會看到作者給開發者提供的文檔說明。‘Class that implemets a condition variable’寫得很明白,這是一個用來記錄線程狀態的類。

 

1. Condition對象初始化

從這段代碼可以看出,Condition使用了threading模塊的Rlock類,關於Rlock的用法可以看我之前寫的一篇文章python同步原語--線程鎖 。在對象初始化的同時,將Rlock的請求鎖和釋放鎖方法賦給了內部的self.acquire和self.release對象方法。當初始化對象同時初始化這兩個方法,也就是說,每個對象在實例化的時候都會實例一個新的可重入鎖(RLock)。這樣可以避免不同對象(condition實例對象)間對類中共用方法的爭奪,避免出現死鎖的問題。

 

 

這段代碼非常的重要。如果熟悉python的上下文管理的朋友應該一看就明白,這是上下文管理中的進入和退出操作。當在調用with時,程式會自動調用_ _enter_ _方法,在程式執行完畢,退出此上下文環境時,自動調用_ _exit_ _方法。那麼在這裡的_ _enter_ _和_ _exit_ _方法分別有什麼用呢?通過閱讀源碼發現,前者是調用了Rlock的acquier方法(獲取鎖),而後者調用了Rlock的release方法(釋放鎖)。在下麵我會繼續講這兩個方法在類中的作用。

 

2. wait()方法

源碼中對wait()方法的定義是‘Wait  untified  or  until  a  timeout  occurs’。意思是阻塞等待知道有提示(notify)或者超時時間(timeout)的到達。

 

再看看wait()函數的內部邏輯

_is_owned()方法是判斷此Condition對象是否有獲取到鎖,如果沒有獲取到鎖(可能是可重入鎖的獲取次數已經達到預定值,不過這種情況很少發生),就會報出錯誤。接下來是對需要等待的程式進行一些列的處理。先是給這個程式分配鎖,對它的程式空間和內部變數進行封鎖。同時把這個加鎖後的程式放進雙端隊列(deque)‘等待者們’中。

好像wait()方法的功能到此就結束了。但是註意到下麵還有try函數塊,旁邊一行註釋寫著‘restore  state  no matter  what’然後又舉了一個KeyboardInterrupt的異常情況。意思是當出現了例如鍵盤輸入ctrl+C這類操作的時候,程式如何退出阻塞。如果在調用wait方法的時候沒有傳入timeout參數,那麼,等待者程式就會重新獲取鎖。如果有timeout參數,就會根據參數來確定退出阻塞的時間。這就是為什麼我們有時在輸入ctrl+C強行退出阻塞的時候,程式會等待一會兒才給出退出程式的提示的原因。

 

 3. notify()方法

接下來這個notify()方法在Condition類中也是非常的重要(queue模塊內部也調用了這個函數)

notify()方法內部實現:

notify直接翻譯過來就是‘提示’的意思。那麼為什麼Condition對象需要‘提示’呢?閱讀源碼下來,其真正的功能不是提示,而是鎖的釋放,並且在釋放了指定數量的waiters之後,順便將他們從‘等待者們’隊列中刪除。如果直接理解為提示,就會很難理解了。但這是老外在定義函數時的寫法,本人的理解是,有點像給阻塞的程式發出信號(提示),停止阻塞(釋放鎖),這麼理解應該也算勉強解釋得過去吧。

 

Condition內部另外還有一個notify_all()方法,這個方法對‘等待者們’隊列中的所有的程式都發出‘提示’,釋放鎖,而沒有像notify中那樣有數量n的限制。

源碼:

 

那麼總結上面的Condititon內部的方法實現,可以看出,Condition類是為了實現一種狀態的‘保存’,即在多線程編程的情況下,由於線程間共用空間而容易引發錯誤,往往需要讓一些線程先執行,而後面的線程等待(阻塞)。那麼如果這些程式需要阻塞等待,就會調用Condition類實例對象的wait方法,當結束等待的信號發出時,就會調用Condition的notify方法對隊列中的程式進行釋放鎖操作。

 

二、關於SegmaphoreBoundedSegmaphore

如果在主機執行IO密集型任務的時候再執行這種短時間內完成大量任務(多線程)的程式時,電腦就有很大可能會宕機。

這時候就可以為這段程式添加一個計數器(counter)功能,來限制一個時間點內的線程數量。當每次進行IO操作時,都需要向segmaphore請求資源(鎖),如果沒有請求到,就阻塞等待,請求成功才就像執行任務。

 

那麼segmaphore的內部實現是怎樣的呢?實質上segmaphore也是鎖,其內部也是通過Lock和Condition實現的。Lock是單鎖,而segmaphore是可以自己定義的多鎖。在初始化segmaphore時,需要傳入參數counter。當線程向segmaphore請求資源(鎖)時,內部的counter會自動減1。當釋放資源(鎖)的時,counter就會自動加1。

segmaphore主要有兩個方法,acquire()和release()方法。

1. acquire()方法

官方的定義:

def acquire(self, blocking=True, timeout=None):

當內部的counter(源碼實際上是用value變數保存)等於0的時候,其他線程acquire會阻塞。這個時候,之前向segmaphore發出請求並獲得鎖的線程,它們如果同時執行完任務並希望釋放鎖時,那麼鎖的釋放是隨機的。任何一個完成任務的線程都會釋放鎖,這個順序跟線程向請求的時間和任務完成的時間是沒有任何關係的。

參數的解析:

1)blocking:預設為True,當線程請求不到資源的時候,會阻塞等待。如果設置為False,則線程請求不到資源時不會阻塞。

2)timeout:如果設置blocking = True,即預設值時,經過timeout時間會退出阻塞。

 

2. release()方法

這個方法與Lock的release方法很像,具體可以看看我之前寫的關於鎖的一篇文章。

鏈接:python同步原語--線程鎖 

源碼:

解析:

當一個實例請求釋放鎖的時候,segmaphore內部的_value會自動加1,同時調用notify方法,將被鎖住的線程‘喚醒’。

 

 

三、關於Event類

閱讀源碼知道,Event是也基於Condition和Lock實現的

 

1. set()方法

在 python--線程同步原語 這篇文章我曾經寫過一個案例,在進程中調用一次event.set()函數就可以一次性通知(釋放)所有阻塞的等待的鎖。其內部實現的原理在這裡,最關鍵的一個方法是notify_all()。

在調用set()方法的時候,方法內部會將_flags設置為True,即等待的事件會退出阻塞。

 

2. clear()方法

clear()方法不同作太多解析了,就是內部的_flags重新設置為False

 

3. wait()方法

wait()方法的定義:

def wait(self, timeout=None):

內部實現:

原理還是很簡單的,實際上Event的wait()方法正是調用了Condition中的實例方法wait()。調用wait()方法的時候可以傳入參數timeout(超時時間),作為Event事件自動退出阻塞的時間界限。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 現要獲取box中,除了第一個之外的其他的div : 其中n後面的數字,是幾就是從第幾個開始獲取。 例子中從第二個div開始獲取, 所以是 n+2 ...
  • 一 簡述JavaScript及其在瀏覽器中的地位 (一) 瀏覽器主要構成 雖然不同瀏覽器之間存在差異(如Google Chrome,Firefox,Safari和IE等),但單從瀏覽器構成來說,大同小異,大致可歸結為如下幾類: 1.User Interface(用戶界面):所謂用戶界面,就是通過瀏覽 ...
  • 作者: 八月未見 博客: https://www.cnblogs.com/jmtm/ 以下內容我僅嘗試了Firefox瀏覽器,其他瀏覽器效果未知。 嘗試做一個 CSS 寫的角標,因為不能把它移到角落去,所以只能用偽類把兩邊擋住,假裝是一個梯形的角標。 <div id="mark"> <h1>未見八月 ...
  • QQ音樂介面播放經常換, 最開始 url: `http://ws.stream.qqmusic.qq.com/${musicData.songid}.m4a?fromtag=46` 然後 url:`http://ws.stream.qqmusic.qq.com/C100${musicData.son ...
  • 一、前提: 微信測試號,用微信開發者工具測試 二、簡單覆述文檔: 1、引入JS文件 在需要調用JS介面的頁面引入如下JS文件,(支持https):http://res.wx.qq.com/open/js/jweixin-1.4.0.js 如需進一步提升服務穩定性,當上述資源不可訪問時,可改訪問:ht ...
  • 啦啦啦,小白福音來啦!零基礎的前端開發初學者看過來!這一波良心推薦的【Web前端學習路線】乾貨,不談虛的,直接來談每個階段要學習的內容 首先,給大家分享一張以 企業崗位需求為導向 Web前端技能點圖 我還是要推薦下我自己創建的web前端資料分享群606721798,這是web前端學習交流的地方,不管 ...
  • webSocket是什麼 webSocket是HTML5新出的一種協議,底層是基於TCP/IP協議的。跟http沒有關係,只是復用了http握手通道,用來升級協議。 webSocket的作用 輪詢:客戶端以一定的時間間隔向服務端發出請求,以頻繁請求的方式來保持客戶端和伺服器端的同步。缺點: 瀏覽器需 ...
  • 概述 1、瞭解springboot的作用 2、構建第一個springboot項目 一、springboot的作用 ① 原先在構建SSM項目的時候,可以感覺到,在一些不是很大的項目,構建配置文件的過程所需的時間花費甚至超過項目本身的業務,每次構建一個新項目都得搞各種配置文件(xml\configura ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...