1. 程式人生 > >Python線程二

Python線程二

change com 當前 初始 運行 ide 情況下 windows test

轉自:https://www.cnblogs.com/chengd/articles/7770898.html

1. threading.Lock()

import threading

balance = 0
lock = threading.Lock()

def change_it(n):
    # 先存後取,結果應該為0:
    global balance
    balance = balance + n
    balance = balance - n

def run_thread(n):
    for i in range(100000):
        # 先要獲取鎖:
        lock.acquire()
        
try: # 放心地改吧: change_it(n) finally: # 改完了一定要釋放鎖: lock.release() if __name__ == "__main__": t1 = threading.Thread(target=run_thread, args=(5,)) t2 = threading.Thread(target=run_thread, args=(8,)) t1.start() t2.start() t1.join() t2.join()
print(balance)

當多個線程同時執行lock.acquire()時,只有一個線程能成功地獲取鎖,然後繼續執行代碼,其他線程就繼續等待直到獲得鎖為止。

獲得鎖的線程用完後一定要釋放鎖,否則那些苦苦等待鎖的線程將永遠等待下去,成為死線程。所以我們用try...finally來確保鎖一定會被釋放。

2、threading.Rlock()

RLock允許在同一線程中被多次acquire。而Lock卻不允許這種情況。註意:如果使用RLock,那麽acquire和release必須成對出現,即調用了n次acquire,必須調用n次的release才能真正釋放所占用的鎖。

import
threading # Lock對象 lock = threading.Lock() def test1(): lock.acquire() lock.acquire() # 產生了死瑣。 print("test1") lock.release() lock.release() # RLock對象 rLock = threading.RLock() def test2(): rLock.acquire() rLock.acquire() # 在同一線程內,程序不會堵塞。 print("test2") rLock.release() rLock.release() if __name__ == "__main__": t1 = threading.Thread(target=test1, args=()) t2 = threading.Thread(target=test2, args=()) t1.start() t2.start() t2.join() t1.join()

RLock允許嵌套。

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() res = run1() print(--------between run1 and run2-----) res2 = run2() lock.release() print(res,res2)

  t = threading.Thread(target=run3)
  t.start()

3. threading.active_count() 返回當前存活的線程對象的數量

通過計算len(threading.enumerate())長度而來

4. threading.current_thread() 返回當前線程對象

import time
import threading

def run():
    thread = threading.current_thread()
    print(%s is running...% thread.getName())    #返回線程名稱
    time.sleep(10)    #休眠10S方便統計存活線程數量

if __name__ == "__main__":
    #設置thread的名稱
    t = threading.Thread(target=run, name="test_thread")
    t.start()

    print(%s is running... % threading.current_thread().getName())
    print("thread count:%d" % threading.active_count())
    print("thread count:%d" % len(threading.enumerate()))

    t.join()

5. threading.enumerate()返回當前存在的所有線程對象的列表

6.threading.get_ident() 返回線程pid

7. threading.main_thread()

import time
import threading

def run():
    print("get the main_thread name is %s" % threading.main_thread().getName())
    print("pid:%s" % threading.get_ident())
    print(ThreadName is :%s % threading.enumerate())  # 返回所有線程對象列表
    time.sleep(10)

if __name__ == "__main__":
    #設置thread的名稱
    t = threading.Thread(target=run, name="test_thread")
    t.start()

    t.join()

8. threading.Condition()

可以把Condiftion理解為一把高級的鎖,它提供了比Lock, RLock更高級的功能,允許我們能夠控制復雜的線程同步問題。

threadiong.Condition在內部維護一個鎖對象(默認是RLock,可被多次acquire),可以在創建Condigtion對象的時候把鎖對象作為參數傳入。

Condition也提供了acquire, release方法,其含義與鎖的acquire, release方法一致,其實它只是簡單的調用內部鎖對象的對應的方法而已。

Condition還提供wait方法、notify方法、notifyAll方法(特別要註意:這些方法只有在占用鎖(acquire)之後才能調用,否則將會報RuntimeError異常。)

wait([timeout]):線程掛起,直到收到一個notify通知或者超時(可選的,浮點數,單位是秒s)才會被喚醒繼續運行。

wait()必須在已獲得鎖前提下才能調用,否則會觸發RuntimeError。調用wait()會釋放鎖,直至該線程被Notify()、NotifyAll()或者超時線程又重新獲得鎖.

notify(n=1):通知其他線程,那些掛起的線程接到這個通知之後會開始運行,默認是通知一個正等待該condition的線程,最多則喚醒n個等待的線程。

notify()必須在已獲得鎖前提下才能調用,否則會觸發RuntimeError。notify()不會主動釋放鎖。

notifyAll(): 如果wait狀態線程比較多,notifyAll的作用就是通知所有線程(這個一般用得少)(不知道是否會產生線程驚群

捉迷藏的遊戲:

一個藏(Hider),一個找(Seeker)

戲的規則如下:

cond = threading.Condition()

1. 遊戲開始之後,Seeker加鎖cond.acquire(),蒙上眼睛後 cond.notify() 通知Hider已經蒙眼,

2. 遊戲開始之後,Hider加鎖cond.acquire(),cond.wait() 等待Seeker的通知(已經蒙眼),

3. Hider收到Seeker蒙眼通知之後,進行躲藏,在完成躲藏之後cond.notify()通知Seeker已經躲藏好,並cond.wait()等待Seeker找到他的通知

4、Seeker接收到通知(Hider完成躲藏)之後,就開始找Hider,並在找到Hider向Hider發出通知cond.notify()

問題!!!如果超過1分鐘沒有找到躲藏者,判Seeker輸,怎麽弄?

嘗試,cond.wait(60) 加上使用一個全局bool類型的值,結果發現cond.wait(60)在超時之後並不會喚醒,不知道是什麽原因,我的測試環境是Windows

import time
import threading

def Seeker(cond, name):
    time.sleep(2)
    cond.acquire()#可多次acquire
    print(%s :我已經把眼睛蒙上了!% name)
    cond.notify()
    cond.wait()
    for i in range(3):
        print(%s is finding!!!% name)
        time.sleep(2)
    print("yeah, find the hider")
    cond.notify()
    cond.release()
    print(%s :我贏了!% name)

def Hider(cond, name):
    cond.acquire()
    cond.wait()
    for i in range(2):
        print(%s is hiding!!!% name)
        time.sleep(3)
    print(%s :我已經藏好了,你快來找我吧!% name)
    cond.notify()
    cond.wait()
    cond.release()
    print(%s :被你找到了,唉~^~!% name)

if __name__ == "__main__":
    cond = threading.Condition()
    seeker = threading.Thread(target=Seeker, args=(cond, seeker))
    hider = threading.Thread(target=Hider, args=(cond, hider))
    seeker.start()
    time.sleep(0.1)
    hider.start()

9. threading.Semaphore和BoundedSemaphore

Semaphore:Semaphore 在內部管理著一個計數器。

調用 acquire() 會使這個計數器 -1,release() 則是+1(可以多次release(),所以計數器的值理論上可以無限).計數器的值永遠不會小於 0,當計數器到 0 時,再調用 acquire() 就會阻塞,直到其他線程來調用release()

BoundedSemaphore:類似於Semaphore;不同在於BoundedSemaphore 會檢查內部計數器的值,並保證它不會大於初始值,如果超了,就引發一個 ValueError。

多數情況下,semaphore 用於守護限制訪問(但不限於 1)的資源,如果 semaphore 被 release() 過多次,這意味著存在 bug

import time
import threading

def run(n):
    # 獲得信號量,信號量減一
    semaphore.acquire()
    time.sleep(1)
    print("run the thread: %s" % n)

    # 釋放信號量,信號量加一
    semaphore.release()
    #semaphore.release()    # 可以多次釋放信號量,每次釋放計數器+1
    #semaphore.release()    # 可以多次釋放信號量,每次釋放計數器+1



if __name__ == "__main__":
    semaphore = threading.Semaphore(2)#semaphore計數器初始化為2

    for i in range(10):
        t = threading.Thread(target=run, args=(i,))
        t.start()

    while threading.active_count() != 1:
        time.sleep(0.1)
    else:
        print(----all threads done---)

    print("----------main thread finish-----------")

import time
import threading


def run(n):
    # 獲得信號量,信號量減一
    semaphore.acquire()
    time.sleep(1)
    print("run the thread: %s" % n)

    # 釋放信號量,信號量加一
    try:
        semaphore.release()
    except ValueError as e:
        print(e)



if __name__ == "__main__":
    semaphore = threading.BoundedSemaphore(2)#內部計數器的初始值,後續操作不允許計數器超過初始值

    for i in range(10):
        t = threading.Thread(target=run, args=(i,))
        t.start()

    while threading.active_count() != 1:
        time.sleep(0.1)
    else:
        print(----all threads done---)

    print("----------main thread finish-----------")

Python線程二