Python 线程同步锁, 信号量
同步锁
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