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