Python 線程同步鎖, 信號量
阿新 • • 發佈:2018-07-29
sleep 圖片 for 初始 image import lock 管理 img
同步鎖
import time, threading
def addNum():
global num
num -= 1
num = 100
thread_list = []
for i in range(100):
t = threading.Thread(target=addNum)
t.start()
thread_list.append(t)
for t in thread_list:
t.join()
print(‘final num:‘, num)
運行結果:
final num: 0
import time, threading def addNum(): global num #num -= 1 tmp = num time.sleep(0.00001) num = tmp - 1 num = 100 thread_list = [] for i in range(100): t = threading.Thread(target=addNum) t.start() thread_list.append(t) for t in thread_list: t.join() print(‘final num:‘, num) 運行結果: final num: 93 或 final num: 91 或 final num: 94
原因:
第一個程序中,num -= 1 這種寫法,程序執行動作太快(完成這個動作在 cup 切換的時間內)
第二個程序中,把 num -= 1 , 加入了 sleep 時間,100個線程存在沒有執行完就進行了切換,導致全局的 num 沒有正常返回。引用下大神的圖發現總結得非常好:
在上面的例子中 使用 join 方法會把整個線程停住,造成了串行,失去了多線程的意義,我們只需要在涉及到計算公共數據的時候串行執行即可。
使用同步鎖處理計算公共的數據
import time, threading def addNum(): global num lock.acquire() tmp = num time.sleep(0.00001) num = tmp - 1 lock.release() num = 100 lock = threading.Lock() thread_list = [] for i in range(100): t = threading.Thread(target=addNum) t.start() thread_list.append(t) for t in thread_list: t.join() print(‘final num:‘, num) 運算結果: final num: 0
線程死鎖和遞歸鎖
import threading, time class myThread(threading.Thread): def doA(self): lockA.acquire() print(self.name, "gotlockA", time.ctime()) time.sleep(3) lockB.acquire() print(self.name, "gotlockB", time.ctime()) lockB.release() lockA.release() def doB(self): lockB.acquire() print(self.name, "gotlockB", time.ctime()) time.sleep(2) lockA.acquire() print(self.name, "gotlockA", time.ctime()) lockA.release() lockB.release() def run(self): self.doA() self.doB() if __name__ == ‘__main__‘: lockA = threading.Lock() lockB = threading.Lock() threads = [] for i in range(5): threads.append(myThread()) for t in threads: t.start() for t in threads: t.join() #運行結果: Thread-1 gotlockA Sat Jul 28 15:09:31 2018 Thread-1 gotlockB Sat Jul 28 15:09:34 2018 Thread-1 gotlockB Sat Jul 28 15:09:34 2018 Thread-2 gotlockA Sat Jul 28 15:09:34 2018
使用遞歸鎖
import threading, time
class myThread(threading.Thread):
def doA(self):
lock.acquire()
print(self.name, "gotlockA", time.ctime())
time.sleep(3)
lock.acquire()
print(self.name, "gotlockB", time.ctime())
lock.release()
lock.release()
def doB(self):
lock.acquire()
print(self.name, "gotlockB", time.ctime())
time.sleep(2)
lock.acquire()
print(self.name, "gotlockA", time.ctime())
lock.release()
lock.release()
def run(self):
self.doA()
self.doB()
if __name__ == ‘__main__‘:
lock = threading.RLock()
threads = []
for i in range(5):
threads.append(myThread())
for t in threads:
t.start()
for t in threads:
t.join()
運行結果:
Thread-1 gotlockA Sat Jul 28 15:19:35 2018
Thread-1 gotlockB Sat Jul 28 15:19:38 2018
Thread-1 gotlockB Sat Jul 28 15:19:38 2018
Thread-1 gotlockA Sat Jul 28 15:19:40 2018
Thread-3 gotlockA Sat Jul 28 15:19:40 2018
Thread-3 gotlockB Sat Jul 28 15:19:43 2018
Thread-3 gotlockB Sat Jul 28 15:19:43 2018
Thread-3 gotlockA Sat Jul 28 15:19:45 2018
Thread-5 gotlockA Sat Jul 28 15:19:45 2018
Thread-5 gotlockB Sat Jul 28 15:19:48 2018
Thread-5 gotlockB Sat Jul 28 15:19:48 2018
Thread-5 gotlockA Sat Jul 28 15:19:50 2018
Thread-4 gotlockA Sat Jul 28 15:19:50 2018
Thread-4 gotlockB Sat Jul 28 15:19:53 2018
Thread-4 gotlockB Sat Jul 28 15:19:53 2018
Thread-4 gotlockA Sat Jul 28 15:19:55 2018
Thread-2 gotlockA Sat Jul 28 15:19:55 2018
Thread-2 gotlockB Sat Jul 28 15:19:58 2018
Thread-2 gotlockB Sat Jul 28 15:19:58 2018
Thread-2 gotlockA Sat Jul 28 15:20:00 2018
信號量
信號量用來控制線程並發數的,BoundedSemaphore或Semaphore管理一個內置的計數 器,每當調用acquire()時-1,調用release()時+1,計數器不能小於0,當計數器為 0時,acquire()將阻塞線程至同步鎖定狀態,直到其他線程調用release()。(類似於停車位的概念)。
BoundedSemaphore與Semaphore的唯一區別在於前者將在調用release()時檢查計數 器的值是否超過了計數器的初始值,如果超過了將拋出一個異常。
import threading, time
class myThread(threading.Thread):
def run(self):
if semaphore.acquire():
print(self.name)
time.sleep(5)
semaphore.release()
if __name__ == "__main__":
semaphore = threading.Semaphore(5)
thrs = []
for i in range(20):
thrs.append(myThread())
for t in thrs:
t.start()
#運行結果:
Thread-1
Thread-2
Thread-3
Thread-4
Thread-5
Thread-6
Thread-7
Thread-9
Thread-10
Thread-8
Thread-11
Thread-13
Thread-14
Thread-12
Thread-15
Thread-18
Thread-16
Thread-17
Thread-19
Thread-20
import threading, time
class myThread(threading.Thread):
def run(self):
if semaphore.acquire():
print(self.name)
time.sleep(5)
semaphore.release()
if __name__ == "__main__":
semaphore = threading.BoundedSemaphore(5)
thrs = []
for i in range(20):
thrs.append(myThread())
for t in thrs:
t.start()
#運行結果:
Thread-1
Thread-2
Thread-3
Thread-4
Thread-5
Thread-6
Thread-8
Thread-10
Thread-9
Thread-7
Thread-12
Thread-14
Thread-15
Thread-13
Thread-11
Thread-16
Thread-17
Thread-20
Thread-19
Thread-18
Python 線程同步鎖, 信號量