Python3.x:threading module線程鎖馅袁、遞歸鎖、信號量

線程鎖

大家已經(jīng)知道了同一個進(jìn)程下的線程數(shù)據(jù)之間可以共享荒辕,也知道多線程中有GIL鎖汗销,一個時刻只有一線程在運行,所以說就是有很多線程在修改這些共享數(shù)據(jù)抵窒,那么不是同時運行的話修改數(shù)據(jù)會不會出現(xiàn)錯誤呢弛针?在Python2中就會出現(xiàn)這種情況,當(dāng)你開啟了很多條線程李皇,然后這些線程一起修改全局變量時削茁,最后得出的結(jié)果可能跟期望的不太一樣

在Python2中出現(xiàn)的錯誤情況

在這個時候Python就提供了另一把鎖,給用戶的鎖掉房,叫做線程鎖茧跋,可以在多個線程操作共享數(shù)據(jù)時更加有規(guī)律,來防止操作數(shù)據(jù)失誤的情況出現(xiàn)卓囚,下面我們就了解一下如何使用線程鎖

import threading


def run():
    # 獲取鎖
    lock.acquire()
    # 聲明全局變量num
    global num
    # num+=1
    num += 1
    # 釋放鎖
    lock.release()


# 生成線程鎖實例
lock = threading.Lock()
num = 0

# 開啟1000個線程
for i in range(1000):
    t = threading.Thread(target=run)
    t.start()

print("-----all thread has finshed")
print("num:", num)

這里要注意的事獲取鎖與釋放鎖之間的這一段所操作的數(shù)據(jù)量不是很大瘾杭,如果數(shù)據(jù)量很大,需要的時間很多哪亿,那么程序就會變成串行

在Python3中這種情況已經(jīng)不會出現(xiàn)了富寿,但是在2中的這種情況與處理方法還是要了解,并且锣夹,在操作共享數(shù)據(jù)時页徐,不管Python2還是Python3,都要加上線程鎖银萍,這是最好的做法

遞歸鎖

接下來我們?nèi)チ私饬硪环N情況变勇,就是鎖中鎖(遞歸鎖),我們分出一個線程贴唇,使用線程鎖之后里面再調(diào)用別的函數(shù)搀绣,然后調(diào)用的這個函數(shù)中再使用線程鎖的話就不能再使用Lock()實例了,不然就會出現(xiàn)死循環(huán)錯誤戳气,這是因為一把鎖對應(yīng)一個鑰匙链患,鎖里面再加一把鎖就會導(dǎo)致程序分不清哪把鑰匙開哪把鎖,導(dǎo)致程序一直在鎖中出不來瓶您,如下

import threading


def run1():
    print("grab the first part data")
    # 獲取鎖
    lock.acquire()
    global num
    num += 1
    # 釋放鎖
    lock.release()
    return num


def run2():
    print("grab the second part data")
    # 獲取鎖
    lock.acquire()
    global num2
    num2 += 1
    # 釋放鎖
    lock.release()
    return num2


def run3():
    # 獲取鎖
    lock.acquire()
    # 去跑run1
    res = run1()
    print('--------between run1 and run2-----')
    # 去跑run2
    res2 = run2()
    # 釋放鎖
    lock.release()
    print(res, res2)


if __name__ == '__main__':
    # 初始化兩個為0的變量
    num, num2 = 0, 0
    # 生成lock實例
    lock = threading.Lock()
    # 開始10個線程
    for i in range(10):
        # 線程跑的是run3
        t = threading.Thread(target=run3)
        t.start()

# 判讀是否有多個線程麻捻,有多個就繼續(xù)打印纲仍,只剩一個說明子線程都執(zhí)行完了,只剩主線程了贸毕,然后跳出循環(huán)程序結(jié)束
# 可以用之前學(xué)到的join()方法來實現(xiàn)一樣的效果
while threading.active_count() != 1:
    print(threading.active_count())
else:
    print('----all threads done---')
    print(num, num2)
程序進(jìn)入死循環(huán)

可以看到郑叠,一直打印線程數(shù)11,說明一直有11個線程在活躍明棍,說明分出的10個線程一直在運行不結(jié)束乡革,這個時候就不能使用Lock()了,而是使用RLock()摊腋,讓我們修改下再來運行試試



看來沸版,只要將Lock改為RLock就可以解決這種鎖中鎖(遞歸鎖)的情況了

信號量

信號量的用法跟線程鎖非常的相似,其實其中的原理與線程鎖并沒有多大的區(qū)別兴蒸,只不過線程鎖鎖住一個線程在運行和修改數(shù)據(jù)视粮,而信號量可以自己控制同一時刻運行幾個線程和幾個線程修改數(shù)據(jù),也就是設(shè)置最大同時運行的線程數(shù)

import threading
import time


def run(n):
    # 獲取信號量
    semaphore.acquire()
    print('task %s is running' % n)
    # 暫停1s方便看出一次運行幾個線程
    time.sleep(1)
    # 釋放信號量
    semaphore.release()


if __name__ == '__main__':
    # 生成信號量實例并設(shè)置信號量為5
    semaphore = threading.BoundedSemaphore(5)
    # 開啟50個線程
    for i in range(50):
        t = threading.Thread(target=run, args=(i,))
        t.start()

# 線程沒有運行完就不退出 
while threading.active_count() != 1:
    pass
else:
    print('----all threads done---')

這里可以自己運行一下类咧,很容易可以看出一次運行五個線程

雖然我們看到的是一次執(zhí)行五個線程馒铃,但并不是五個一組五個一組分組執(zhí)行的蟹腾,因為這五個線程同時完成痕惋,所以我們看不出來,但是其中的過程是執(zhí)行完一個線程放進(jìn)去一個線程娃殖,假如這五個中有兩個先完成值戳,那么就會立刻再放進(jìn)去兩個,也就是說這五個線程之間不會互相等待炉爆,這個設(shè)置的信號量5不是按5來分組堕虹,而是同時運行的線程最大數(shù),可以寫多個執(zhí)行時間不同的函數(shù)然后一次執(zhí)行幾個來證明這一點

轉(zhuǎn)載請注明出處

python自學(xué)技術(shù)互助扣扣群:670402334

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末芬首,一起剝皮案震驚了整個濱河市赴捞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌郁稍,老刑警劉巖赦政,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泻红,死亡現(xiàn)場離奇詭異冲粤,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)危纫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門财破,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掰派,“玉大人,你說我怎么就攤上這事左痢∶蚁郏” “怎么了系洛?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長亿眠。 經(jīng)常有香客問我碎罚,道長,這世上最難降的妖魔是什么纳像? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任荆烈,我火速辦了婚禮,結(jié)果婚禮上竟趾,老公的妹妹穿的比我還像新娘憔购。我一直安慰自己,他們只是感情好岔帽,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布玫鸟。 她就那樣靜靜地躺著,像睡著了一般犀勒。 火紅的嫁衣襯著肌膚如雪屎飘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天贾费,我揣著相機(jī)與錄音钦购,去河邊找鬼。 笑死褂萧,一個胖子當(dāng)著我的面吹牛押桃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播导犹,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼唱凯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了谎痢?” 一聲冷哼從身側(cè)響起磕昼,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎节猿,沒想到半個月后票从,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡沐批,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年纫骑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片九孩。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡先馆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出躺彬,到底是詐尸還是另有隱情煤墙,我是刑警寧澤梅惯,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站仿野,受9級特大地震影響铣减,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜脚作,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一葫哗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧球涛,春花似錦劣针、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至从祝,卻和暖如春襟己,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背牍陌。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工擎浴, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人呐赡。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓退客,卻偏偏與公主長得像骏融,于是被迫代替她去往敵國和親链嘀。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 引用自多線程編程指南應(yīng)用程序里面多個線程的存在引發(fā)了多個執(zhí)行線程安全訪問資源的潛在問題档玻。兩個線程同時修改同一資源有...
    Mitchell閱讀 1,994評論 1 7
  • Java8張圖 11怀泊、字符串不變性 12、equals()方法误趴、hashCode()方法的區(qū)別 13霹琼、...
    Miley_MOJIE閱讀 3,707評論 0 11
  • 在開發(fā)Java多線程應(yīng)用程序中,各個線程之間由于要共享資源凉当,必須用到鎖機(jī)制枣申。Java提供了多種多線程鎖機(jī)制的實現(xiàn)方...
    千淘萬漉閱讀 6,912評論 1 33
  • 從三月份找實習(xí)到現(xiàn)在,面了一些公司看杭,掛了不少忠藤,但最終還是拿到小米、百度楼雹、阿里模孩、京東尖阔、新浪、CVTE榨咐、樂視家的研發(fā)崗...
    時芥藍(lán)閱讀 42,253評論 11 349
  • 密林狹窄介却,這劍陣狹長,如同靈蛇形狀块茁,元力貫通齿坷,將極修堂眾人的力量集結(jié)一處,首尾相應(yīng)数焊,擊尾則首應(yīng)胃夏,擊腰則首尾相應(yīng),雖...
    榮蔓蔓閱讀 303評論 3 3