最近一个朋友面试 Python 后端,被问了个经典题:“你说说什么是锁?Python 里有哪些锁?”他回来跟我吐槽:“这玩意平时都直接用,没想到一上来就问原理,我脑袋直接死锁了。”哈哈,他这反应也太真实了,别说面试了,我平时写多线程时也就顺手一 Lock(),背后到底多少种锁,真要细扒起来,还挺有意思。
什么是锁?程序员心中的“交通红绿灯”
锁这东西,说白了就是用来控制资源访问的机制。多线程环境里,多个线程可能会争抢同一个变量,比如你在转账,一个线程刚把钱扣掉,另一个线程又来查余额,看到的是扣之前的值,尴尬了。
锁就像红绿灯,线程来前先看灯,红灯就乖乖等,绿灯才可以执行,这样就避免了资源混乱的“车祸”。
Python里的锁类型大致分几类
虽然 Python 的多线程受 GIL 限制,真正的并行很难,但线程安全的概念还得有。我们来一个个说。
threading.Lock:标准锁,入门必备
最常见的就是这个 Lock(),又叫互斥锁(mutex)。一次只能一个线程进,其他都得等它释放。
它是“非可重入”的,什么意思?就是同一个线程不能连续拿两次这个锁,不然就死锁,像下面这样:
所以推荐用 with lock: 语法,避免健忘党出bug。
threading.RLock:可以反复进的锁
RLock 是“可重入锁”,一个线程可以多次拿这个锁,只要释放次数跟获取次数对得上,就不会死锁。适合函数里再调用另一个加锁函数的场景。
为啥会有这个锁?你想想,类里的方法 A 调用方法 B,两者都加锁,如果用 Lock 就挂了,线程自己把自己锁死;用 RLock 就不会出问题。
threading.Semaphore:限量供应的锁
这是“信号量锁”,可以控制最多有几个线程能进入临界区。
场景很典型,比如限制数据库连接池最多开5个连接。用 Semaphore(5) 就能搞定。
说实话,这个我平时写爬虫控制并发的时候用得最多。
threading.Condition:锁的进阶版,可配合 wait/notify
Condition 让你线程之间可以“对话”,一个线程可以等另一个线程说“可以开始了”,适合消费者-生产者模型。
用起来复杂点,但优雅多了,不然线程间全靠瞎猜。
threading.Event:布尔值的锁?
不是传统意义上的“锁”,但也能用来协调线程执行时机。相当于一个共享的“开关”,开了大家就跑,不开大家都等。
用在定时任务、启动同步很方便,逻辑清楚。
小技巧和误区:锁不是性能优化工具!
很多朋友刚开始学多线程,喜欢无脑上锁,结果越锁越慢。
我觉得应该遵循这个原则:
- • 如果资源共享,必须锁;
- • 如果是 CPU 密集任务,考虑用多进程;
- • 如果是 IO 密集任务,线程 + 异步组合更香;
- • 如果锁多到自己都绕晕,说明设计出问题了。
还有人喜欢用双重锁,比如:
兄弟,这种写法没意义,因为两个线程可能都看到没锁,接着一起冲进去。要记住,锁要么上,要么不上,别耍小聪明。
写代码加锁就像谈恋爱:一旦加了,责任就来了
锁这个东西,用得好能保命,用不好就是事故现场。我朋友面试完说:“锁这题太冷门了。”我说你怕是没见过生产系统半夜死锁报警。
如果你面试碰到这题,建议别死记硬背名词,直接举个例子,把每种锁的用法讲出来,哪怕只讲 Lock 和 RLock,讲细一点比你背五种锁管用。
讲真,程序员的世界,锁就是“人设管理器”,合理上锁,才能不崩。锁得对,代码不“绿”你;锁错了,不仅代码绿你,老板也可能绿你。
以上就是“python面试题:解释一下什么是锁,有哪几种锁?”的详细内容,想要了解更多Python教程欢迎持续关注编程学习网。扫码二维码 获取免费视频学习资料
- 本文固定链接: http://phpxs.com/post/13047/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料