簡單探討一下python線程鎖
為什么需要線程鎖
當(dāng)我們訪問一些特殊的數(shù)據(jù)時,需要保證該數(shù)據(jù)的原子性,比如: 文章的閱讀量、文章的點贊量等。我們必須要確保這些共享數(shù)據(jù)必須是原子性的,否則的話,多線程同時訪問的時候,可能會出現(xiàn)異常情況,什么是原子性呢?原子性是指一個操作是不可能被中途中斷的,要不全部完成,要不沒有完成,這么說,可能不理解,下面舉個例子來說明一下原子性的重要性:
比如我們寫一個程序,來模擬10個人點贊,最后輸出閱讀量的值,代碼如下:
代碼初看好像沒什么問題,反正核心點就是閱讀量+1,當(dāng)運行就,就出現(xiàn)問題了,
上述代碼,運行了5次,出現(xiàn)了5次不一樣的結(jié)果。這就是出現(xiàn)了競爭,所以我們需要加一個鎖,來確保該閱讀量函數(shù)的原子性。
線程鎖使用
python
中的threading
模塊,提供的鎖就只有一種,我們使用Lock
定義鎖,例如:
Lock = threading.Lock()
如果需要對資源進(jìn)行上鎖的話,使用acquire
方法即可,例如:
Lock.acquire()
如果需要對資源進(jìn)行解鎖的話,使用release
方法即可,例如:
Lock.release()
除此之外,threading
模塊還提供了RLock
可重入鎖,可重入鎖的作用和普通鎖一樣,用于保護(hù)資源,以保證并發(fā)訪問不會出現(xiàn)問題,但是與普通鎖不同的是,可重入鎖允許同一個線程在持有鎖的情況下多次獲取該鎖而不會發(fā)生死鎖。但是在持有多少次鎖,也必須釋放多少次鎖,否則會出現(xiàn)問題。
案例說明線程鎖
上述我們介紹了線程鎖,這里將addReaderCount
進(jìn)行加鎖和解鎖的操作,代碼如下:
上述代碼在源代碼的基礎(chǔ)上,在最開始使用Lock
定義了一個鎖,而后再函數(shù)開始之前進(jìn)行一個加鎖acquire()
,這樣的話,其他函數(shù)在執(zhí)行的時候,發(fā)現(xiàn)這個是已經(jīng)鎖住了的,所以會等待,等待解鎖后(releas()
)再進(jìn)行該函數(shù),而函數(shù)又會加鎖,如此往復(fù),能夠確保在同一時刻,addReaderCount
函數(shù)只執(zhí)行一次。
執(zhí)行程序結(jié)果為:
可以發(fā)現(xiàn),這次的結(jié)果閱讀量的值終于符合我們的預(yù)期了。
實現(xiàn)一個讀寫鎖
在python
中,原生是沒有讀寫鎖的,只能借助第三方來實現(xiàn),這里我們可以實現(xiàn)一個簡單的讀寫鎖。
在寫之前,我們需要先了解下讀寫鎖的作用到底是什么?讀寫鎖將資源拆分為讀和寫2種操作,讀鎖允許多個線程同時讀取共享資源,提高并發(fā)性能。但是當(dāng)需要修改共享資源的時候,只能允許一個線程修改該共享資源,并且在修改完畢前,不允許讀請求,以便造成數(shù)據(jù)不一致。所以操作完畢后,開放讀請求。
這里為了實驗,寫了一個最簡單的讀寫鎖,安全性和效率都得不到保證,若想使用讀寫鎖,可以使用第三方的讀寫鎖。
我們自己寫的讀寫鎖代碼如下:
上述代碼,我們實現(xiàn)了一個讀寫鎖類RWLock
,其中有4個方法,分別為:
writeLock
:寫鎖writeUnlock
:釋放寫鎖readLock
:讀鎖readUnlock
: 釋放讀鎖
由于讀鎖可以同一時刻被調(diào)用,所以我們使用的變量readCount
來定義的,等需要讀鎖的是,readCount
會+1,可以一直調(diào)用下去,而如果需要寫鎖的時候,這里是先將寫鎖變量Locked
定義為True
,若此時再次調(diào)用讀寫,會讓其等待,而在寫鎖中,會等待讀鎖讀取完畢后(readCount
為0的時候),再進(jìn)行寫鎖的請求。寫鎖執(zhí)行完畢后,會將Locked
給重置為False
。
這里寫一個小的調(diào)用方法來調(diào)用一下:
上述代碼,在reads
和writes
方法中,分表調(diào)用我們之前定義的讀鎖和寫鎖,代碼中定義了9個線程,分別是調(diào)用了6次讀,以及3次寫。
效果我們來看下:
從上述結(jié)果中,我們不難發(fā)現(xiàn),在沒有寫鎖情況下,我們使用讀鎖,可以訪問同一資源,當(dāng)使用寫鎖后,讀鎖會暫停,當(dāng)寫鎖執(zhí)行完畢后,讀鎖才會繼續(xù)批量執(zhí)行。
總結(jié)
本篇文章簡單探討了一下python
線程鎖,并且舉了一個點贊的案例,來說明某些資源/函數(shù)需要原子性操作的時候,為避免資源競爭,所以需要在使用過程中,增加一個鎖,以保證其原子性,由于python
原生沒有讀寫鎖,需要依賴于第三方,所以最后我們寫了一個最簡單的讀寫鎖。
到此這篇關(guān)于簡單探討一下python線程鎖的文章就介紹到這了,更多相關(guān)python 線程鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python 中類的構(gòu)造方法 __New__的妙用
這篇文章主要介紹了Python 中類的構(gòu)造方法 New的妙用,Python 的類中,所有以雙下劃線__包起來的方法,叫魔術(shù)方法,魔術(shù)方法在類或?qū)ο蟮哪承┦录l(fā)出后可以自動執(zhí)行,讓類具有神奇的魔力。下面就來學(xué)習(xí)文章的詳細(xì)內(nèi)容把2021-10-10pytorch利用Dataset讀取數(shù)據(jù)報錯問題及解決
這篇文章主要介紹了pytorch利用Dataset讀取數(shù)據(jù)報錯問題及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09python高效過濾出文件夾下指定文件名結(jié)尾的文件實例
今天小編就為大家分享一篇python高效過濾出文件夾下指定文件名結(jié)尾的文件實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-10-10Python中字符串轉(zhuǎn)換為列表的常用方法總結(jié)
本文將詳細(xì)介紹Python中將字符串轉(zhuǎn)換為列表的八種常用方法,每種方法都具有其獨特的用途和適用場景,文中的示例代碼講解詳細(xì),感興趣的可以了解下2023-11-11解決tensorflow1.x版本加載saver.restore目錄報錯的問題
今天小編就為大家分享一篇解決tensorflow1.x版本加載saver.restore目錄報錯的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-07-07selenium+python實現(xiàn)自動化登錄的方法
這篇文章主要介紹了selenium+python實現(xiàn)自動化登錄的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-09-09