前言
这几年一直在it行业里摸爬滚打,一路走来,不少总结了一些python行业里的高频面试,看到大部分初入行的新鲜血液,还在为各样的面试题答案或收录有各种困难问题
于是乎,我自己开发了一款面试宝典,希望能帮到大家,也希望有更多的Python新人真正加入从事到这个行业里,让python火不只是停留在广告上。
微信小程序搜索:Python面试宝典
或可关注原创个人博客:https://lienze.tech
也可关注微信公众号,不定时发送各类有趣猎奇的技术文章:Python编程学习
死锁
不合理的同步方式,将会造成死锁,死锁有大致如下两种
递归死锁
当一把锁在一个进程下重复使用而并未及时释放时,会造成死锁
自己持有锁时,二次加锁,这就是重复加锁,会导致死锁
- 实现递归死锁
from multiprocessing import Process,Lock,RLock
def func(lock):
print('开启进程')
with lock:# 加锁
print('获取到lock锁')
with lock:
print('再次获取lock锁') # 重复加锁
def main():
lock = Lock()
p1 = Process(target=func,args=(lock,))
p2 = Process(target=func,args=(lock,))
p1.start()
p1.join()
p2.start()
p2.join()
if __name__ == '__main__':
main()
- 解决递归死锁,通过可重入锁
RLock
;重用锁在单独环境下多次使用,会在内部维护当前一个使用次数,可以在当前环境多次使用
但是对应的,每次acquire被记录了次数,也只有对应次数release才可以释放锁,否则其他进程、线程依旧无法获锁,这个锁只是给定了多次重复持锁的办法
from multiprocessing import Process,Lock,RLock
def func(lock):
print('开启进程')
if lock.acquire(1):
print('获取到lock锁')
lock.acquire()
lock.release()
lock.release()
def main():
lock = RLock()
p1 = Process(target=func,args=(lock,))
p2 = Process(target=func,args=(lock,))
p1.start()
p1.join()
p2.start()
p2.join()
if __name__ == '__main__':
main()
以上这段代码,可以持有两次锁,对应释放两次锁,代码正常执行
争夺锁
当两个以上进程获取了对方接下来所需要的锁,从而进入等待资源状态,也会造成死锁
- 比如
from multiprocessing import Process,Lock
import time
import sys
def a(l_a,l_b):
with l_a:
print('持有a锁')
sys.stdout.flush()
time.sleep(1) #等待b进程获取b锁,实现死锁
with l_b:
print('持有b锁')
def b(l_a,l_b):
with l_b:
print('持有b锁')
with l_a:
print('持有a锁')
def main():
l_a = Lock()
l_b = Lock()
p1 = Process(target=a,args=(l_a,l_b))
p2 = Process(target=b,args=(l_a,l_b))
p1.start()
p2.start()
p1.join()
p2.join()
if __name__ == '__main__':
main()
- 注意:由于竞争锁的进程之间不构成可以程过结束运行的程序,所以缓冲区不会被
Python
自动刷新;一般缓冲刷新的动作在程序结束或手动刷新时,所以需要我们在进程中手动通过sys.stdout.flush()
进行输出缓冲区的刷新
解决争夺锁的办法是程序员在编写代码的时候不要脑子犯抽,要明确每一把锁的意义和加持顺序