一、Lock版鎖機制
多線程都是在同一個進程中運行的。因此在進程中的全局變量所有線程都是可共享的。這就造成了一個問題,因爲線程執行的順序都是無序的,有可能會造成數據錯誤,代碼如下:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import threading
VALUE = 0
def add_value():
global VALUE
for i in range(10000):
VALUE += 1
print('VALUE值爲:', VALUE)
def main():
for x in range(2):
t = threading.Thread(target=add_value)
t.start()
if __name__ == '__main__':
main()
因此需要在修改全局變量的時候給它加個鎖,改善後代碼:
示例一:增加數字
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# acquire:上鎖
# release:解鎖
import threading
VALUE = 0
Lock = threading.Lock()
def add_value():
global VALUE
Lock.acquire()
for i in range(10000):
VALUE += 1
print('VALUE值爲:', VALUE)
Lock.release()
def main():
for x in range(2):
t = threading.Thread(target=add_value)
t.start()
if __name__ == '__main__':
main()
示例二:生產者和消費者模型
模型:生產者生產 ===> 全局變量 ===> 消費者消費變量
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import threading,random,time
VALUE = 1000
Lock = threading.Lock()
class Product(threading.Thread):
def run(self):
global VALUE
while True:
m = random.randint(100,500)
Lock.acquire()
VALUE += m
print('%s 生成了數字 %s ,現在數字大小爲 %s ' %(threading.current_thread(),m,VALUE))
Lock.release()
time.sleep(0.5)
class Consumer(threading.Thread):
def run(self):
global VALUE
while True:
m = random.randint(200,600)
Lock.acquire()
if VALUE >= m:
VALUE -= m
print('%s 消費了數字 %s ,現在數字大小爲 %s ' %(threading.current_thread(),m,VALUE))
else:
print('數字 %s 太小' %VALUE)
Lock.release()
time.sleep(0.5)
def main():
for x in range(3):
t = Consumer(name='消費者線程%d' %(x))
t.start()
for x in range(5):
t = Product(name='生產者線程%d' %(x))
t.start()
if __name__ == '__main__':
main()
二、Condition版鎖機制
由於上鎖是一個很耗費CPU資源的行爲,因此 Lock鎖機制 方式不是很友好。還有一種是通過 threading.Condition
來實現。 threading.Condition
可以在沒有數據的時候處於阻塞等待狀態,一旦有了合適的數據,可以使用 notify 相關的函數來通知其他等待的線程。這樣可以不用做一些無用的上鎖和解鎖的操作,提高程序的性能。,threading.Condition類似threading.Lock,可以在修改全局數據的時候進行上鎖,也可以在修改完畢後進行解鎖。
acquire:上鎖。
release:解鎖。
wait:將當前線程處於等待狀態,並且會釋放鎖。可以被其他線程使用notify和notify_all函數喚醒。被喚醒後會繼續等待上鎖,上鎖後繼續執行下面的代碼。
notify:通知某個正在等待的線程,默認是第1個等待的線程。
notify_all:通知所有正在等待的線程。notify和notify_all不會釋放鎖。並且需要在release之前調用
#!/usr/bin/env python
#-*- coding:utf-8 -*-
# 生產者和消費者模型
import threading,random,time
VALUE = 1000
cLock = threading.Condition()
class Product(threading.Thread):
def run(self):
global VALUE
while True:
m = random.randint(100,500)
cLock.acquire()
VALUE += m
print('%s 生成了數字 %s ,現在數字大小爲 %s ' %(threading.current_thread(),m,VALUE))
cLock.notify_all() # 通知wait()
cLock.release()
time.sleep(0.5)
class Consumer(threading.Thread):
def run(self):
global VALUE
while True:
m = random.randint(200,600)
cLock.acquire()
if VALUE >= m:
VALUE -= m
print('%s 消費了數字 %s ,現在數字大小爲 %s ' %(threading.current_thread(),m,VALUE))
else:
print('數字 %s 太小' %VALUE)
cLock.wait() # 全局值太小了,那就等待,直到通知時候再去排隊
cLock.release()
time.sleep(0.5)
def main():
for x in range(3):
t = Consumer(name='消費者線程%d' %(x))
t.start()
for x in range(2):
t = Product(name='生產者線程%d' %(x))
t.start()
if __name__ == '__main__':
main()