小編寫(xiě)這篇文章的一個(gè)主要目的,主要是來(lái)給大家介紹關(guān)于python的一些事情,python的使用場(chǎng)景是比較的多的,主要涉及到其中的一些方方面面,那么,它的并發(fā)場(chǎng)景使用方法是什么呢?下面就給大家詳細(xì)解答下。
前言
如果你學(xué)過(guò)操作系統(tǒng),那么對(duì)于鎖應(yīng)該不陌生。鎖的含義是線(xiàn)程鎖,可以用來(lái)指定某一個(gè)邏輯或者是資源同一時(shí)刻只能有一個(gè)線(xiàn)程訪問(wèn)。這個(gè)很好理解,就好像是有一個(gè)房間被一把鎖鎖住了,只有拿到鑰匙的人才能進(jìn)入。每一個(gè)人從房間門(mén)口拿到鑰匙進(jìn)入房間,出房間的時(shí)候會(huì)把鑰匙再放回到門(mén)口。這樣下一個(gè)到門(mén)口的人就可以拿到鑰匙了。這里的房間就是某一個(gè)資源或者是一段邏輯,而拿取鑰匙的人其實(shí)指的是一個(gè)線(xiàn)程。
加鎖的原因
我們明白了鎖的原理,不禁有了一個(gè)問(wèn)題,我們?yōu)槭裁葱枰i呢,它在哪些場(chǎng)景當(dāng)中會(huì)用到呢?
其實(shí)它的使用場(chǎng)景非常廣,我們舉一個(gè)非常簡(jiǎn)單的例子,就是淘寶買(mǎi)東西。我們都知道商家的庫(kù)存都是有限的,賣(mài)掉一個(gè)少一個(gè)。假如說(shuō)當(dāng)前某個(gè)商品庫(kù)存只剩下一個(gè),但當(dāng)下卻有兩個(gè)人同時(shí)購(gòu)買(mǎi)。兩個(gè)人同時(shí)購(gòu)買(mǎi)也就是有兩個(gè)請(qǐng)求同時(shí)發(fā)起購(gòu)買(mǎi)請(qǐng)求,如果我們不加鎖的話(huà),兩個(gè)線(xiàn)程同時(shí)查詢(xún)到商品的庫(kù)存是1,大于0,進(jìn)行購(gòu)買(mǎi)邏輯之后,同時(shí)減一。由于兩個(gè)線(xiàn)程同時(shí)執(zhí)行,所以最后商品的庫(kù)存會(huì)變成-1。
顯然商品的庫(kù)存不應(yīng)該是一個(gè)負(fù)數(shù),所以我們需要避免這種情況發(fā)生。通過(guò)加鎖可以完美解決這個(gè)問(wèn)題。我們規(guī)定一次只能有一個(gè)線(xiàn)程發(fā)起購(gòu)買(mǎi)的請(qǐng)求,那么這樣當(dāng)一個(gè)線(xiàn)程將庫(kù)存減到0的時(shí)候,第二個(gè)請(qǐng)求就無(wú)法修改了,就保證了數(shù)據(jù)的準(zhǔn)確性。
代碼實(shí)現(xiàn)
那么在Python當(dāng)中,我們?cè)趺礃觼?lái)實(shí)現(xiàn)這個(gè)鎖呢?
其實(shí)很簡(jiǎn)單,threading庫(kù)當(dāng)中已經(jīng)為我們提供了線(xiàn)程的工具,我們直接拿過(guò)來(lái)用就可以了。我們通過(guò)使用threading當(dāng)中的Lock對(duì)象,可以很輕易的實(shí)現(xiàn)方法加鎖的功能。
import threading class PurchaseRequest: ''' 初始化庫(kù)存與鎖 ''' def __init__(self,initial_value=0): self._value=initial_value self._lock=threading.Lock() def incr(self,delta=1): ''' 加庫(kù)存 ''' self._lock.acquire() self._value+=delta self._lock.release() def decr(self,delta=1): ''' 減庫(kù)存 ''' self._lock.acquire() self._value-=delta self._lock.release()
我們從代碼當(dāng)中就可以很輕易的看出Lock這個(gè)對(duì)象的使用方法,我們?cè)谶M(jìn)入加鎖區(qū)(資源搶占區(qū))之前,我們需要先使用lock.acquire()方法獲取鎖。Lock對(duì)象可以保證同一時(shí)刻只能有一個(gè)線(xiàn)程獲取鎖,只有獲取了鎖之后才會(huì)繼續(xù)往下執(zhí)行。當(dāng)我們執(zhí)行完成之后,我們需要把鎖“放回門(mén)口”,所以需要再調(diào)用一下release方法,表示鎖的釋放。
這里有一個(gè)小問(wèn)題是很多程序員在編程的時(shí)候總是會(huì)忘記release,導(dǎo)致不必要的bug,而且這種分布式場(chǎng)景當(dāng)中的bug很難通過(guò)測(cè)試發(fā)現(xiàn)。因?yàn)闇y(cè)試的時(shí)候往往很難測(cè)試并發(fā)場(chǎng)景,code review的時(shí)候也很容易忽略,因此一旦泄露了還是挺難發(fā)現(xiàn)的。
為了解決這個(gè)問(wèn)題,Lock還提供了一種改進(jìn)的用法,就是使用with語(yǔ)句。with語(yǔ)句我們之前在使用文件的時(shí)候用到過(guò),使用with可以替我們完成try catch以及資源回收等工作,我們只管用就完事了。這里也是一樣,使用with之后我們就可以不用管鎖的申請(qǐng)和釋放了,直接寫(xiě)代碼就行,所以上面的代碼可以改寫(xiě)成這樣:
import threading class PurchaseRequest: ''' 初始化庫(kù)存與鎖 ''' def __init__(self,initial_value=0): self._value=initial_value self._lock=threading.Lock() def incr(self,delta=1): ''' 加庫(kù)存 ''' with self._lock: self._value+=delta def decr(self,delta=1): ''' 減庫(kù)存 ''' with self._lock: self._value-=delta
這樣看起來(lái)是不是清爽很多?
可重入鎖
上面介紹的只是最簡(jiǎn)單的鎖,我們經(jīng)常使用的往往是可重入鎖。
什么叫可重入鎖呢?簡(jiǎn)單解釋一下,就是在一個(gè)線(xiàn)程已經(jīng)持有了鎖的情況下,它可以再次進(jìn)入被加鎖的區(qū)域。但是既然線(xiàn)程還持有鎖沒(méi)有釋放,那么它不應(yīng)該還是在加鎖區(qū)域嗎,怎么會(huì)有需要再次進(jìn)入被加鎖區(qū)域的情況呢?其實(shí)是有的,道理也很簡(jiǎn)單,就是遞歸。
我們把上面的例子稍微改一點(diǎn)點(diǎn),就完全不一樣了。
import threading class PurchaseRequest: ''' 初始化庫(kù)存與鎖 ''' def __init__(self,initial_value=0): self._value=initial_value self._lock=threading.Lock() def incr(self,delta=1): ''' 加庫(kù)存 ''' with self._lock: self._value+=delta def decr(self,delta=1): ''' 減庫(kù)存 ''' with self._lock: self.incr(-delta) 我們關(guān)注一下上面的decr方法,我們用incr來(lái)代替了原本的邏輯實(shí)現(xiàn)了decr。但是有一個(gè)問(wèn)題是decr也是一個(gè)加鎖的方法,需要前一個(gè)鎖釋放了才能進(jìn)入。但它已經(jīng)持有了鎖了,那么這種情況下就會(huì)發(fā)生死鎖。 我們只需要把Lock換成可重入鎖就可以解決這個(gè)問(wèn)題,只需要修改一行代碼。 import threading class PurchaseRequest: ''' 初始化庫(kù)存與鎖 我們使用RLock代替了Lock,也可重入鎖代替了普通鎖 ''' def __init__(self,initial_value=0): self._value=initial_value self._lock=threading.RLock() def incr(self,delta=1): ''' 加庫(kù)存 ''' with self._lock: self._value+=delta def decr(self,delta=1): ''' 減庫(kù)存 ''' with self._lock: self.incr(-delta)
總結(jié)
文章介紹了Python當(dāng)中鎖的使用方法,以及可重入鎖的概念。在并發(fā)場(chǎng)景下開(kāi)發(fā)和調(diào)試都是一個(gè)比較困難的工作,稍微不小心就會(huì)踩到各種各樣的坑,死鎖只是其中一種比較常見(jiàn)并且比較容易解決的問(wèn)題,除此之外還有很多其他各種各樣的問(wèn)題。
綜上所述,這篇文章就給大家介紹到這里了,希望可以給大家?guī)?lái)幫助。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/128418.html
摘要:測(cè)試吞吐量的時(shí)候,是通過(guò)每一種實(shí)現(xiàn)都重復(fù)測(cè)試超過(guò)次,每一次都運(yùn)行秒以上,以保證系統(tǒng)足夠預(yù)熱,下面的結(jié)果都是第次之后平均每秒吞吐量。以我的經(jīng)驗(yàn)看,教學(xué)和開(kāi)發(fā)中的無(wú)鎖算法,不僅能顯著改善吞吐量同時(shí)他們也提供更低的延遲。 上周在由Heinz Kabutz通過(guò)JCrete?組織的開(kāi)放空間會(huì)議(unconference)上,我參加一個(gè)新的java規(guī)范 JSR166?StampedLock 的審查...
摘要:如果某線(xiàn)程并未使用很多操作,它會(huì)在自己的時(shí)間片內(nèi)一直占用處理器和。在中使用線(xiàn)程在和等大多數(shù)類(lèi)系統(tǒng)上運(yùn)行時(shí),支持多線(xiàn)程編程。守護(hù)線(xiàn)程另一個(gè)避免使用模塊的原因是,它不支持守護(hù)線(xiàn)程。 這一篇是Python并發(fā)的第四篇,主要介紹進(jìn)程和線(xiàn)程的定義,Python線(xiàn)程和全局解釋器鎖以及Python如何使用thread模塊處理并發(fā) 引言&動(dòng)機(jī) 考慮一下這個(gè)場(chǎng)景,我們有10000條數(shù)據(jù)需要處理,處理每條...
摘要:有可能,會(huì)造成優(yōu)先級(jí)反轉(zhuǎn)或者饑餓現(xiàn)象。悲觀鎖在中的使用,就是利用各種鎖。對(duì)于而言,其是獨(dú)享鎖。偏向鎖,顧名思義,它會(huì)偏向于第一個(gè)訪問(wèn)鎖的線(xiàn)程,大多數(shù)情況下鎖不僅不存在多線(xiàn)程競(jìng)爭(zhēng),而且總是由同一線(xiàn)程多次獲得。 理解鎖的基礎(chǔ)知識(shí) 如果想要透徹的理解java鎖的來(lái)龍去脈,需要先了解以下基礎(chǔ)知識(shí)。 基礎(chǔ)知識(shí)之一:鎖的類(lèi)型 按照其性質(zhì)分類(lèi) 公平鎖/非公平鎖 公平鎖是指多個(gè)線(xiàn)程按照申請(qǐng)鎖的順序來(lái)獲...
摘要:中關(guān)于線(xiàn)程的標(biāo)準(zhǔn)庫(kù)是,之前在版本中的在之后更名為,無(wú)論是還是都應(yīng)該盡量避免使用較為底層的而應(yīng)該使用。而與線(xiàn)程相比,協(xié)程尤其是結(jié)合事件循環(huán)無(wú)論在編程模型還是語(yǔ)法上,看起來(lái)都是非常友好的單線(xiàn)程同步過(guò)程。 項(xiàng)目地址:https://git.io/pytips 要說(shuō)到線(xiàn)程(Thread)與協(xié)程(Coroutine)似乎總是需要從并行(Parallelism)與并發(fā)(Concurrency)談起...
摘要:此時(shí)線(xiàn)程和會(huì)再有一個(gè)線(xiàn)程能夠獲取寫(xiě)鎖,假設(shè)是,如果不采用再次驗(yàn)證的方式,此時(shí)會(huì)再次查詢(xún)數(shù)據(jù)庫(kù)。而實(shí)際上線(xiàn)程已經(jīng)把緩存的值設(shè)置好了,完全沒(méi)有必要再次查詢(xún)數(shù)據(jù)庫(kù)。 大家知道了Java中使用管程同步原語(yǔ),理論上可以解決所有的并發(fā)問(wèn)題。那 Java SDK 并發(fā)包里為什么還有很多其他的工具類(lèi)呢?原因很簡(jiǎn)單:分場(chǎng)景優(yōu)化性能,提升易用性 今天我們就介紹一種非常普遍的并發(fā)場(chǎng)景:讀多寫(xiě)少場(chǎng)景。實(shí)際工作...
閱讀 1066·2023-01-14 11:38
閱讀 1062·2023-01-14 11:04
閱讀 901·2023-01-14 10:48
閱讀 2377·2023-01-14 10:34
閱讀 1147·2023-01-14 10:24
閱讀 1026·2023-01-14 10:18
閱讀 654·2023-01-14 10:09
閱讀 733·2023-01-14 10:02