互斥锁:牺牲了效率,得到了数据安全,串行了。 缺点:acqueire后其他进程必须等到该进程release后才能继续拿到锁,可能会出现死锁情况。
def demo():
mutex.acquire()
print('%s 拿到了A锁' % current_thread().getName())
time.sleep(2)
mutex.release()
print('%s 拿到了B锁' % current_thread().getName())
if __name__ == '__main__':
mutex = Lock()
t = Thread(target=demo)
t1 = Thread(target=demo)
t2 = Thread(target=demo)
t.start()
t1.start()
t2.start()
执行结果:
>>>Thread-1 拿到了A锁
>>>Thread-1 拿到了B锁
>>>Thread-2 拿到了A锁
>>>Thread-2 拿到了B锁
>>>Thread-3 拿到了A锁
>>>Thread-3 拿到了B锁
递归锁
在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。
这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁,二者的区别是:递归锁可以连续acquire多次,而互斥锁只能acquire一次
总结:
RLock可以多次acquire,每次acquire就相当于conuter+1,只要counter不为0,别的进程就无法拿到我锁。
from threading import Lock,RLock,Semaphore,Thread,current_thread
import time
def demo():
mutexA.acquire()
print('%s 拿到了A锁' % current_thread().getName())
time.sleep(1)
mutexB.acquire()
print('%s 拿到了B锁' % current_thread().getName())
mutexB.release()
mutexA.release()
demo1()
def demo1():
mutexB.acquire()
print('%s 拿到了B锁' % current_thread().getName())
time.sleep(1)
mutexA.acquire()
print('%s 拿到了A锁' % current_thread().getName())
mutexA.release()
mutexB.release()
if __name__ == '__main__':
mutexA = RLock()
mutexB = mutexA
t = Thread(target=demo)
t1 = Thread(target=demo)
t2 = Thread(target=demo)
t.start()
t1.start()
t2.start()
信号量:
信号量也是一把锁,可以指定信号量为5,对比互斥锁同一时间只能有一个任务抢到锁去执行,信号量同一时间可以有5个任务拿到锁去执行,如果说互斥锁是合租房屋的人去抢一个厕所,那么信号量就相当于一群路人争抢公共厕所,公共厕所有多个坑位,这意味着同一时间可以有多个人上公共厕所,但公共厕所容纳的人数是一定的,这便是信号量的大小
from threading import Thread,Semaphore
import threading
import time
def func():
with sm:
print('%s get sm' % threading.current_thread().getName())
time.sleep(1)
if __name__ == '__main__':
sm = Semaphore(3)
for i in range(10):
t=Thread(target=func)
t.start()